How can I read consul SRV records in my go application? - dns

I am trying to implement consul for service discovery, and I am having trouble with two things: connecting to a custom DNS server, and formatting my net.LookupSRV() request.
Here is what I'm trying to look up from within my go app:
$ dig #127.0.0.1 -p 8600 serviceb.service.consul SRV
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> #127.0.0.1 -p 8600 serviceb.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4511
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 2
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;serviceb.service.consul. IN SRV
;; ANSWER SECTION:
serviceb.service.consul. 0 IN SRV 1 1 80 az1-serviceb1.node.dc1.consul.
serviceb.service.consul. 0 IN SRV 1 1 80 az2-serviceb2.node.dc1.consul.
;; ADDITIONAL SECTION:
az1-serviceb1.node.dc1.consul. 0 IN A 10.6.41.22
az2-serviceb2.node.dc1.consul. 0 IN A 10.6.41.20
;; Query time: 6 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Fri May 16 15:09:28 2014
;; MSG SIZE rcvd: 275
and here is the relevant code. (I know it's wrong, but just so you can see what I'm trying to do)
cname, addrs, err := net.LookupSRV("serviceb", "service", "consul")
log.Printf("%+v %+v %+v", cname, addrs, err)
and the output:
2014/05/16 15:24:31 [] lookup _serviceb._service.consul: no such host
Any help would be appreciated! thanks

Try to use a more sharp tool such as the github.com/miekg/dns package. Last time I looked at it, it allowed to control virtually every bit of the client-side setup to do DNS resolution.

Consul does support strict RFC 2782 and lookup can be done using the standard library only:
resolver := &net.Resolver{
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, network, "127.0.0.1:8600")
},
}
_, addrs, err := resolver.LookupSRV(
context.Background(), "svcname", "tcp", "consul",
)

While this doesn't answer your exact question, I find it's an easier way to access service data for greenfield apps.
It's quite easy to call the HTTP API with net/http:
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
resp, _ := http.Get("http://localhost:8500/v1/catalog/service/serviceb")
body, _ := ioutil.ReadAll(resp.Body)
fmt.Print(string(body))
}
The basics of the HTTP API are documented in the Services Guide.

The best way is to use PreparedQueries, as Posted here
import (
"fmt"
consulapi "github.com/hashicorp/consul/api"
)
func main() {
config := consulapi.DefaultConfig()
consul, err := consulapi.NewClient(config)
if err != nil {
fmt.Println(err)
}
preparedQuery := consul.PreparedQuery()
queryID, _, err := preparedQuery.Create(&consulapi.PreparedQueryDefinition{
Name: "DnsQuery",
Service: consulapi.ServiceQuery{
Service: "serviceb",
OnlyPassing: true,
},
}, &consulapi.WriteOptions{})
if err != nil {
fmt.Println(err)
}
res, _, _ := preparedQuery.Execute(queryID, &consulapi.QueryOptions{})
for _, node := range res.Nodes {
fmt.Println(node.Service.Address, node.Service.Port)
}

Related

SRV lookup request doesn't return an IP address

I am writing an XMPP client. The RFC says I need to connect to the server (like this one) using a SRV query.
When I use the trust_dns_resolver crate to do so, the query seems to be empty. Is this the normal behavior?
use trust_dns_resolver::Resolver;
use trust_dns_resolver::Name;
use std::str::FromStr;
fn main() {
let resolver = Resolver::from_system_conf().unwrap();
match resolver.srv_lookup(Name::from_str("_xmpp-client._tcp.xmpp.jp").unwrap()) {
Ok(response) => {
for ip in response.ip_iter() {
println!("{}", ip.to_string());
}
},
Err(e) => println!("{}", e),
}
}
The dig SRV _xmpp-client._tcp.xmpp.jp command line return the following:
; <<>> DiG 9.16.18 <<>> SRV _xmpp-client._tcp.xmpp.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16710
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 2605a5d828b394e22ffbec3e61010461a668fc990570d859 (good)
;; QUESTION SECTION:
;_xmpp-client._tcp.xmpp.jp. IN SRV
;; ANSWER SECTION:
_xmpp-client._tcp.xmpp.jp. 23 IN SRV 20 10 5222 sapporo.xmpp.jp.
_xmpp-client._tcp.xmpp.jp. 23 IN SRV 30 10 5222 gw.lb.xmpp.jp.
_xmpp-client._tcp.xmpp.jp. 23 IN SRV 10 10 5222 tokyo.xmpp.jp.
;; Query time: 13 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: mer. juil. 28 09:16:49 CEST 2021
;; MSG SIZE rcvd: 183
I will have three IP addresses right ?
I think I'm misunderstanding something, but I don't know what.
It's ok if the SRV lookup return no IP address. in my case, the query return only few tuples composed of a domain name and a port number. After getting them, I have to resolve each one to get its IP address with its port number.
The trust_dns_proto crate is mandatory to deal with SRV lookup. So I add it to the Cargo.toml file, and the compiler stop crying...
Then I can write the following code to extract both port number and domain name:
use trust_dns_resolver::Resolver;
use trust_dns_resolver::Name;
use std::str::FromStr;
[...]
let resolver = Resolver::from_system_conf().unwrap();
match resolver.srv_lookup(Name::from_str("_xmpp-client._tcp.xmpp.jp.").unwrap()) {
Ok(response) => {
for srv in response.iter() {
println!("Port number:\t{}", srv.port());
println!("Domain name:\t{}\n", srv.target().to_utf8());
// have to resolve the domain name here
}
println!("{}", response.query().name());
},
Err(e) => println!("{}", e),
}
Thanks to Zeppi. His solution was far from perfect, but it put me on the right track to finding my own.

why server can't find pihole.service.consul: NXDOMAIN and how can I fix this?

I have following configuration for consul.
{
"service": {
"name": "pihole",
"Address": "192.168.0.15",
"tags": [
"pi"
],
"port": 8165,
"check": {
"args": [
"curl",
"192.168.0.15"
],
"interval": "10s"
}
}
}
using dig i get no error now,
$ dig #127.0.0.1 -p 8600 pihole.service.consul
; <<>> DiG 9.9.7-P3 <<>> #127.0.0.1 -p 8600 pihole.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63573
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pihole.service.consul. IN A
;; ANSWER SECTION:
pihole.service.consul. 0 IN A 192.168.0.15
;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Sun Aug 30 23:02:34 BST 2020
;; MSG SIZE rcvd: 66
but when I do nslookup, i get the error server can't find pihole.service.consul: NXDOMAIN
$ nslookup pihole.service.consul
Server: 192.168.0.15
Address: 192.168.0.15#53
** server can't find pihole.service.consul: NXDOMAIN
I actually have a pihole running at this ip address 192.168.0.15
on the consul health check is passing.
2020-08-30T23:10:58.707+0100 [DEBUG] agent: Check status updated: check=service:pihole status=passing
In the command dig #127.0.0.1 -p 8600 pihole.service.consul you explicitly instructed host to use server 127.0.0.1 and port 8600.
Nslookup uses nameserver from your /etc/resolv.conf file and port 53 by default.
You can try
nslookup pihole.service.consul 127.0.0.1 -port=8600

Node.js I can't resolve TXT record

I have an question about dns.resolveTxt.
https://nodejs.org/api/dns.html#dns_dns_resolvetxt_hostname_callback
Basically I can resolve TXT record, but for specific DNS zone, I can't resolve TXT record. For example, microsoft.com and so on.
I wrote the following code.
var dns = require('dns');
dns.resolveTxt('microsoft.com', (err, record) => {
console.log(record);
});
Does any one know the issue?
import * as dns from "dns";
dns.resolveTxt('microsoft.com', (err, addresses) => {
console.log(JSON.stringify(addresses));
});
outputs
[["v=spf1 include:_spf-a.microsoft.com include:_spf-b.microsoft.com include:_spf-c.microsoft.com include:_spf-ssg-a.microsoft.com include:spf-a.hotmail.com include:_spf1-meo.microsoft.com -all"],["d365mktkey=3uc1cf82cpv750lzk70v9bvf2"]
,["adobe-idp-site-verification=8aa35c528af5d72beb19b1bd3ed9b86d87ea7f24b2ba3c99ffcd00c27e9d809c"],["fg2t0gov9424p2tdcuo94goe9j"],["apple-domain-verification=0gMeaYyYy6GLViGo"],["d365mktkey=4d8bnycx40fy3581petta4gsf"],["docusign=d5a3737
c-c23c-4bd0-9095-d2ff621f2840"],["adobe-sign-verification=c1fea9b4cdd4df0d5778517f29e0934"],["google-site-verification=Zv1IvEEZg4N9wbEXpBSSyAiIjDyyB3S-fzfFClb7D1E"],["google-site-verification=8-zFCaUXhhPcvN29EVw2RvtASDCaDPQ02L1HJ8Om8I0
"],["google-site-verification=pjPOauSPcrfXOZS9jnPPa5axowcHGCDAl1_86dCqFpk"],["google-site-verification=1TeK8q0OziFl4T1tF-QR65JkzHZ1rcdgNccDFp78iTk"],["8RPDXjBzBS9tu7Pbysu7qCACrwXPoDV8ZtLfthTnC4y9VJFLd84it5sQlEITgSLJ4KOIA8pBZxmyvPujuUvh
Og=="],["docusign=52998482-393d-46f7-95d4-15ac6509bfdd"],["facebook-domain-verification=fwzwhbbzwmg5fzgotc2go51olc3566"]]
So, clearly seems to work fine.
The problem is DNS results over 512 bytes long. As near as I can tell, Node's dns.resolve* functions do not support EDNS, which allows up to 4096 byte responses, at least as of Node 14. Given this code:
const { Resolver } = require('dns');
const dns = new Resolver();
dns.resolveTxt(process.argv[2], (err, res) => {
if (err) {
console.log(err);
} else {
console.log(res);
}
});
I get this result:
$ node dns-test2.js google.com
Error: queryTxt ESERVFAIL google.com
at QueryReqWrap.onresolve [as oncomplete] (dns.js:206:19) {
errno: undefined,
code: 'ESERVFAIL',
syscall: 'queryTxt',
hostname: 'google.com'
}
And you can see that dig returns 715 bytes for the same query:
$ dig TXT google.com
; <<>> DiG 9.10.3-P4-Debian <<>> TXT google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32543
;; flags: qr rd ra; QUERY: 1, ANSWER: 9, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;google.com. IN TXT
;; ANSWER SECTION:
google.com. 30 IN TXT "google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ"
google.com. 30 IN TXT "v=spf1 include:_spf.google.com ~all"
google.com. 30 IN TXT "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
google.com. 30 IN TXT "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
google.com. 30 IN TXT "google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o"
google.com. 30 IN TXT "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
google.com. 30 IN TXT "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
google.com. 30 IN TXT "apple-domain-verification=30afIBcvSuDV2PLX"
google.com. 30 IN TXT "MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB"
;; Query time: 4 msec
;; SERVER: 10.0.0.10#53(10.0.0.10)
;; WHEN: Fri Sep 10 21:02:16 UTC 2021
;; MSG SIZE rcvd: 715
Running tcpdump, I see that the node query does not include the UDPsize=4096 option:
TXT? google.com. (28)
Whereas the dig request does:
TXT? google.com. ar: . OPT UDPsize=4096 (39)
A similar query for a TXT record that only returns 244 bytes works fine:
$ node dns-test2.js partechgss.com
[
[ 'ryb3spm2r33rtxl189nqs5n41xxrzmlz' ],
[ 'v=spf1 include:_spf.google.com ~all' ],
[ 'MS=ms32721923' ],
[ 'MS=ms56152555' ]
]
$ dig TXT partechgss.com
; <<>> DiG 9.10.3-P4-Debian <<>> TXT partechgss.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56392
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;partechgss.com. IN TXT
;; ANSWER SECTION:
partechgss.com. 30 IN TXT "MS=ms56152555"
partechgss.com. 30 IN TXT "MS=ms32721923"
partechgss.com. 30 IN TXT "v=spf1 include:_spf.google.com ~all"
partechgss.com. 30 IN TXT "ryb3spm2r33rtxl189nqs5n41xxrzmlz"
;; Query time: 14 msec
;; SERVER: 10.0.0.10#53(10.0.0.10)
;; WHEN: Fri Sep 10 21:15:21 UTC 2021
;; MSG SIZE rcvd: 244
Unfortunately, having identified the problem, I have yet to find a solution. I've opened a bug report against the node.js project on github.

Why does Mesos-DNS not provide a SRV answer?

I have a vagrant box which is running Mesos, Marathon and Chronos (publicly packaged as playa-mesos). It is a sane environment (I have customized to a 192.168.. ip address though) and I can launch different apps incl. docker containerized ones.
I have tried a new demo, where there is a DNS requirement and the mesos application launch definition is as below :
{
"id": "mesos-dns",
"instances": 1,
"cpus": 0.2,
"mem": 50,
"cmd": "/mesos-dns -config=/config.json",
"container": {
"type": "DOCKER",
"docker": {
"image": "mesosphere/mesos-dns:latest",
"network": "HOST"
},
"volumes": [
{
"containerPath": "/config.json",
"hostPath": "/etc/mesos-dns/config.json",
"mode": "RO"
}
]
}
}
The config.json is as under :
{
"zk": "zk://127.0.0.1:2181/mesos",
"refreshSeconds": 60,
"ttl": 60,
"domain": "mesos",
"port": 53,
"resolvers": ["10.0.2.3"],
"timeout": 5,
"email": "root.mesos-dns.mesos"
}
The /etc/resolv.conf contains nameserver 10.0.2.3
Below is the dig response I get to my DNS query; both are shown below :-
dig _webdis-site-m-shop._tcp.marathon.mesos SRV
; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> _webdis-site-m-shop._tcp.marathon.mesos SRV
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 4759
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 8192
;; QUESTION SECTION:
;_webdis-site-m-shop._tcp.marathon.mesos. IN SRV
;; AUTHORITY SECTION:
. 56521 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2016021800 1
800 900 604800 86400
;; Query time: 155 msec
;; SERVER: 10.0.2.3#53(10.0.2.3)
;; WHEN: Thu Feb 18 13:38:21 UTC 2016
;; MSG SIZE rcvd: 143`
As you can see there is no ANSWER and the status NXDOMAIN means that this query resulted in a non-existent domain.
Can someone help me fix this ?
TIA.
This is now fixed. I have taken some thoughts from other posts on SO. I have changed the OOTB setting for ip address etc...
Broadly I added the 127.0.0.1 loopback ip addr, virtualbox generated ip addr (which in my case is 192.168.x.y) and retained the existing nameserver entry.
The results of the dig command is now :-
dig _webdis-site-m-shop._tcp.marathon.mesos SRV
; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> _webdis-site-m-shop._tcp.marathon.mesos SRV
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6284
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;_webdis-site-m-shop._tcp.marathon.mesos. IN SRV
;; ANSWER SECTION:
_webdis-site-m-shop._tcp.marathon.mesos. 60 IN SRV 0 0 31720 webdis-site-m-shop-39847-s0.marathon.mesos.
;; ADDITIONAL SECTION:
webdis-site-m-shop-39847-s0.marathon.mesos. 60 IN A 192.168.56.106
;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Feb 18 16:55:57 UTC 2016
;; MSG SIZE rcvd: 216

Bind9 configuration

I can't understand why my dns server won't work.
i get this, when i testing with "dig"
; <<>> DiG 9.7.3 <<>> connectioon.eu
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 54973
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;connectioon.eu. IN A
;; Query time: 0 msec
;; SERVER: 192.168.1.33#53(192.168.1.33)
;; WHEN: Fri Dec 9 20:14:07 2011
;; MSG SIZE rcvd: 32
named.conf.local:
zone "connectioon.eu" {
type master;
file "/etc/bind/zones/connectioon.eu";
};
zone "21.100.91.in-addr.arpa" {
type master;
file "/etc/bind/zones/192.168.1";
};
I have tried with:
zone "1.168.192.in-addr.arpa" {
type master;
file "/etc/bind/zones/192.168.1";
};
and
zone "192.168.1.in-addr.arpa" {
type master;
file "/etc/bind/zones/192.168.1";
};
the connectioon.eu conf file:
; BIND data file for local loopback interface
;
$TTL 604800
# IN SOA connectioon.eu. voice12345678910.hotmail.com. (
09122011180545 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
# IN NS connectioon.eu.
# IN 91.100.21.28
the 192.168.1 file:
;
; BIND data file for local loopback interface
;
$TTL 604800
# IN SOA connectioon.eu. voice12345678910.hotmail.com. (
09122011184553 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
NS connectioon.eu.
28 PTR connectioon.eu.
my public ip is: 91.100.21.28 and local ip to dns: 192.168.1.33
ps. i using bind9 on ubuntu 11.04
This command :
dig connectioon.eu #91.100.21.28
shows
; <<>> DiG 9.7.3 <<>> connectioon.eu #91.100.21.28
;; global options: +cmd
;; connection timed out; no servers could be reached
Are you sure a name server is listening on port 53 (and is not restricted to local requests) ?
I assume 91.100.21.28 is where your DNS server is meant to be.
(edit: Actually a quick dig connectioon.eu +norecurse #x.nic.eu shows that the primary NS is 91.100.21.28.hostname-generic.arrownet.dk which resolves to 91.100.21.28)
PS: +1 for ziesemer's serverfault-related comment

Resources