Skip to content

Commit fd3cd75

Browse files
rsmsry
authored andcommitted
[dgram] only look up hostname for the requested address family
- [lib/dns.js] dns.lookup takes a new optional argument "family" which should be the integer 4, 6, dns.AF_INET or dns.AF_INET6. Passing a non-false "family" argument makes c-ares explicitly look up addresses for the specified family. - [test/simple/test-c-ares.js] test explicit address family lookups
1 parent 9395786 commit fd3cd75

File tree

3 files changed

+107
-47
lines changed

3 files changed

+107
-47
lines changed

doc/api.markdown

+11
Original file line numberDiff line numberDiff line change
@@ -2515,6 +2515,17 @@ resolves the IP addresses which are returned.
25152515
});
25162516
});
25172517

2518+
### dns.lookup(domain, family=null, callback)
2519+
2520+
Resolves a domain (e.g. `'google.com'`) into the first found A (IPv4) or
2521+
AAAA (IPv6) record.
2522+
2523+
The callback has arguments `(err, address, family)`. The `address` argument
2524+
is a string representation of a IP v4 or v6 address. The `family` argument
2525+
is either the integer 4 or 6 and denotes the family of `address` (not
2526+
neccessarily the value initially passed to `lookup`).
2527+
2528+
25182529
### dns.resolve(domain, rrtype='A', callback)
25192530

25202531
Resolves a domain (e.g. `'google.com'`) into an array of the record types

lib/dgram.js

+23-21
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ function getPool() {
2828
return pool;
2929
}
3030

31+
function dnsLookup(type, hostname, callback) {
32+
var family = (type ? ((type === "udp6") ? 6 : 4) : null);
33+
dns.lookup(hostname, family, function (err, ip, addressFamily) {
34+
if (!err && family && addressFamily !== family) {
35+
err = new Error('no address found in family '+type+' for '+hostname);
36+
}
37+
callback(err, ip, addressFamily);
38+
});
39+
}
40+
3141
function Socket (type, listener) {
3242
events.EventEmitter.call(this);
3343
var self = this;
@@ -103,22 +113,15 @@ Socket.prototype.bind = function () {
103113
} else {
104114
// the first argument is the port, the second an address
105115
this.port = arguments[0];
106-
if (dns.isIP(arguments[1])) {
107-
this.address = arguments[1];
108-
binding.bind(self.fd, port, arguments[1]);
109-
this.emit("listening");
110-
} else {
111-
dns.lookup(arguments[1], function (err, ip, addressType) {
112-
// TODO - only look up proper record for address family
113-
if (err) {
114-
self.emit('error', err);
115-
} else {
116-
self.ip = ip;
117-
binding.bind(self.fd, self.port, ip);
118-
self.emit("listening");
119-
}
120-
});
121-
}
116+
dnsLookup(this.type, arguments[1], function (err, ip, addressFamily) {
117+
if (err) {
118+
self.emit('error', err);
119+
} else {
120+
self.ip = ip;
121+
binding.bind(self.fd, self.port, ip);
122+
self.emit("listening");
123+
}
124+
});
122125
}
123126
}
124127
};
@@ -153,7 +156,7 @@ Socket.prototype.setTTL = function(arg) {
153156
}
154157
};
155158

156-
// translate arguments from JS API into C++ API, after optional DNS lookup
159+
// translate arguments from JS API into C++ API, possibly after DNS lookup
157160
Socket.prototype.send = function(buffer, offset, length) {
158161
var self = this;
159162

@@ -173,13 +176,12 @@ Socket.prototype.send = function(buffer, offset, length) {
173176
}
174177

175178
if (dns.isIP(arguments[4])) {
176-
self.sendto(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
179+
self.sendto(arguments[0], arguments[1], arguments[2], arguments[3],
180+
arguments[4], arguments[5]);
177181
} else {
178182
var port = arguments[3],
179183
callback = arguments[5];
180-
181-
// TODO - only look up proper record for address family
182-
dns.lookup(arguments[4], function (err, ip, addressType) {
184+
dnsLookup(this.type, arguments[4], function (err, ip, addressFamily) {
183185
if (err) { // DNS error
184186
if (callback) {
185187
callback(err);

lib/dns.js

+73-26
Original file line numberDiff line numberDiff line change
@@ -100,46 +100,93 @@ exports.getHostByName = function (domain, callback) {
100100
var net;
101101

102102
// Easy DNS A/AAAA look up
103-
exports.lookup = function (domain, callback) {
104-
var addressType = dns.isIP(domain);
105-
if (addressType) {
106-
process.nextTick(function () {
107-
callback(null, domain, addressType);
108-
});
103+
// lookup(domain, [family,] callback)
104+
exports.lookup = function (domain, family, callback) {
105+
if (arguments.length === 2) {
106+
callback = family;
107+
family = undefined;
108+
} else if (family && family !== 4 && family !== 6) {
109+
family = parseInt(family);
110+
if (family === dns.AF_INET) {
111+
family = 4;
112+
} else if (family === dns.AF_INET6) {
113+
family = 6;
114+
} else if (family !== 4 && family !== 6) {
115+
throw new Error('invalid argument: "family" must be 4 or 6');
116+
}
117+
}
118+
if (!domain) {
119+
callback(null, null, family === 6 ? 6 : 4);
120+
return;
121+
}
122+
var matchedFamily = dns.isIP(domain);
123+
if (matchedFamily) {
124+
callback(null, domain, matchedFamily);
109125
} else {
110-
if (/\w\.local\.?$/.test(domain) ) {
126+
if (/\w\.local\.?$/.test(domain)) {
111127
// ANNOYING: In the case of mDNS domains use NSS in the thread pool.
112128
// I wish c-ares had better support.
113129
process.binding('net').getaddrinfo(domain, 4, function (err, domains4) {
114130
callback(err, domains4[0], 4);
115131
});
116132
} else {
117-
channel.getHostByName(domain, dns.AF_INET, function (err, domains4) {
118-
if (domains4 && domains4.length) {
119-
callback(null, domains4[0], 4);
120-
} else {
121-
channel.getHostByName(domain, dns.AF_INET6, function (err, domains6) {
122-
if (domains6 && domains6.length) {
123-
callback(null, domains6[0], 6);
133+
if (family) {
134+
// resolve names for explicit address family
135+
var af = (family === 4) ? dns.AF_INET : dns.AF_INET6;
136+
channel.getHostByName(domain, af, function (err, domains) {
137+
if (!err && domains && domains.length) {
138+
if (family !== dns.isIP(domains[0])) {
139+
callback(new Error('not found'), []);
124140
} else {
125-
callback(err, []);
141+
callback(null, domains[0], family);
126142
}
127-
});
128-
}
129-
});
143+
} else {
144+
callback(err, []);
145+
}
146+
});
147+
} else {
148+
// first resolve names for v4 and if that fails, try v6
149+
channel.getHostByName(domain, dns.AF_INET, function (err, domains4) {
150+
if (domains4 && domains4.length) {
151+
callback(null, domains4[0], 4);
152+
} else {
153+
channel.getHostByName(domain, dns.AF_INET6,
154+
function (err, domains6) {
155+
if (domains6 && domains6.length) {
156+
callback(null, domains6[0], 6);
157+
} else {
158+
callback(err, []);
159+
}
160+
});
161+
}
162+
});
163+
}
130164
}
131165
}
132166
};
133167

134168

135-
exports.resolve4 = function(domain, callback) { channel.query(domain, dns.A, callback) };
136-
exports.resolve6 = function(domain, callback) { channel.query(domain, dns.AAAA, callback) };
137-
exports.resolveMx = function(domain, callback) { channel.query(domain, dns.MX, callback) };
138-
exports.resolveTxt = function(domain, callback) { channel.query(domain, dns.TXT, callback) };
139-
exports.resolveSrv = function(domain, callback) { channel.query(domain, dns.SRV, callback) };
140-
exports.reverse = function(domain, callback) { channel.query(domain, dns.PTR, callback) };
141-
exports.resolveNs = function(domain, callback) { channel.query(domain, dns.NS, callback) };
142-
169+
exports.resolve4 = function(domain, callback) {
170+
channel.query(domain, dns.A, callback);
171+
};
172+
exports.resolve6 = function(domain, callback) {
173+
channel.query(domain, dns.AAAA, callback);
174+
};
175+
exports.resolveMx = function(domain, callback) {
176+
channel.query(domain, dns.MX, callback);
177+
};
178+
exports.resolveTxt = function(domain, callback) {
179+
channel.query(domain, dns.TXT, callback);
180+
};
181+
exports.resolveSrv = function(domain, callback) {
182+
channel.query(domain, dns.SRV, callback);
183+
};
184+
exports.reverse = function(domain, callback) {
185+
channel.query(domain, dns.PTR, callback);
186+
};
187+
exports.resolveNs = function(domain, callback) {
188+
channel.query(domain, dns.NS, callback);
189+
};
143190

144191
var resolveMap = {
145192
'A' : exports.resolve4,

0 commit comments

Comments
 (0)