Skip to content

Commit

Permalink
feat: impl dns.getServers
Browse files Browse the repository at this point in the history
Close: #3981
  • Loading branch information
Hanaasagi committed Aug 5, 2023
1 parent 78081cb commit 47d9204
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 3 deletions.
85 changes: 85 additions & 0 deletions src/bun.js/api/bun/dns_resolver.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const JSGlobalObject = JSC.JSGlobalObject;
const c_ares = bun.c_ares;

const GetAddrInfoAsyncCallback = fn (i32, ?*std.c.addrinfo, ?*anyopaque) callconv(.C) void;
const INET6_ADDRSTRLEN = if (bun.Environment.isWindows) 65 else 46;
const IANA_DNS_PORT = 53;

const LibInfo = struct {
// static int32_t (*getaddrinfo_async_start)(mach_port_t*,
Expand Down Expand Up @@ -2015,6 +2017,83 @@ pub const DNSResolver = struct {
return promise;
}

pub fn getServers(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
_ = callframe;

var vm = globalThis.bunVM();
var resolver = vm.rareData().globalDNSResolver(vm);
var channel: *c_ares.Channel = switch (resolver.getChannel()) {
.result => |res| res,
.err => |err| {
const system_error = JSC.SystemError{
.errno = -1,
.code = bun.String.static(err.code()),
.message = bun.String.static(err.label()),
};

globalThis.throwValue(system_error.toErrorInstance(globalThis));
return .zero;
},
};

var servers: [*c]c_ares.struct_ares_addr_port_node = undefined;
const r = c_ares.ares_get_servers_ports(channel, &servers);
if (r != c_ares.ARES_SUCCESS) {
const err = c_ares.Error.get(r).?;
globalThis.throwValue(globalThis.createErrorInstance("ares_get_servers_ports error: {s}", .{err.label()}));
return .zero;
}
defer c_ares.ares_free_data(servers);

const values = JSC.JSValue.createEmptyArray(globalThis, 0);

var i: u32 = 0;
var cur = servers;
while (cur != null) : ({
i += 1;
cur = cur.*.next;
}) {
// Formatting reference: https://nodejs.org/api/dns.html#dnsgetservers
// Brackets '[' and ']' consume 2 bytes, used for IPv6 format (e.g., '[2001:4860:4860::8888]:1053').
// Port range is 6 bytes (e.g., ':65535').
// Null terminator '\0' uses 1 byte.
var buf: [INET6_ADDRSTRLEN + 2 + 6 + 1]u8 = undefined;
const family = cur.*.family;

const ip = if (family == std.os.AF.INET6) blk: {
break :blk c_ares.ares_inet_ntop(family, &cur.*.addr.addr6, buf[1..], @sizeOf(@TypeOf(buf)));
} else blk: {
break :blk c_ares.ares_inet_ntop(family, &cur.*.addr.addr4, buf[1..], @sizeOf(@TypeOf(buf)));
};
_ = ip;

var port = cur.*.tcp_port;
if (port == 0) {
port = cur.*.udp_port;
}
if (port == 0) {
port = IANA_DNS_PORT;
}

const size = bun.len(bun.cast([*:0]u8, &buf));
if (port == IANA_DNS_PORT) {
values.putIndex(globalThis, i, JSC.ZigString.init(buf[1..size]).withEncoding().toValueGC(globalThis));
} else {
if (family == std.os.AF.INET6) {
buf[0] = '[';
buf[size] = ']';
const port_slice = std.fmt.bufPrint(buf[size + 1 ..], ":{d}", .{port}) catch unreachable;
values.putIndex(globalThis, i, JSC.ZigString.init(buf[0 .. size + 1 + port_slice.len]).withEncoding().toValueGC(globalThis));
} else {
const port_slice = std.fmt.bufPrint(buf[size..], ":{d}", .{port}) catch unreachable;
values.putIndex(globalThis, i, JSC.ZigString.init(buf[1 .. size + port_slice.len]).withEncoding().toValueGC(globalThis));
}
}
}

return values;
}

comptime {
@export(
resolve,
Expand Down Expand Up @@ -2082,6 +2161,12 @@ pub const DNSResolver = struct {
.name = "Bun__DNSResolver__resolveCname",
},
);
@export(
getServers,
.{
.name = "Bun__DNSResolver__getServers",
},
);
}
// pub fn lookupService(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
// const arguments = callframe.arguments(3);
Expand Down
3 changes: 3 additions & 0 deletions src/bun.js/bindings/ZigGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2860,6 +2860,7 @@ extern "C" EncodedJSValue Bun__DNSResolver__resolveCaa(JSGlobalObject*, JSC::Cal
extern "C" EncodedJSValue Bun__DNSResolver__resolveNs(JSGlobalObject*, JSC::CallFrame*);
extern "C" EncodedJSValue Bun__DNSResolver__resolvePtr(JSGlobalObject*, JSC::CallFrame*);
extern "C" EncodedJSValue Bun__DNSResolver__resolveCname(JSGlobalObject*, JSC::CallFrame*);
extern "C" EncodedJSValue Bun__DNSResolver__getServers(JSGlobalObject*, JSC::CallFrame*);

JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * globalObject, CallFrame* callframe))
{
Expand Down Expand Up @@ -3251,6 +3252,8 @@ void GlobalObject::finishCreation(VM& vm)
JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCname"_s), 2, Bun__DNSResolver__resolveCname, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getServers"_s), 2, Bun__DNSResolver__getServers, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
init.set(dnsObject);
});

Expand Down
5 changes: 5 additions & 0 deletions src/js/node/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// only resolve4, resolve, lookup, resolve6 and resolveSrv are implemented.
const dns = Bun.dns;

function getServers() {
return dns.getServers();
}

function lookup(domain, options, callback) {
if (typeof options == "function") {
callback = options;
Expand Down Expand Up @@ -685,4 +689,5 @@ export default {
resolveTxt,
resolveNaptr,
promises,
getServers,
};
Loading

0 comments on commit 47d9204

Please sign in to comment.