@ai-ecoverse/slicc-kernel 1.136.9 → 1.138.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -358,7 +358,7 @@ function noticeOf(data) {
358
358
  if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === "string"), trees: [] };
359
359
  const notice = data ?? {};
360
360
  const strings = (list) => Array.isArray(list) ? list.filter((p) => typeof p === "string") : [];
361
- return { paths: strings(notice.paths), trees: strings(notice.trees) };
361
+ return { paths: strings(notice.paths), trees: strings(notice.trees), outside: true };
362
362
  }
363
363
 
364
364
  // src/fs/types.ts
@@ -1307,9 +1307,11 @@ var OpfsFs = class {
1307
1307
  for (const path of [...c.paths, ...c.trees]) this.forget(path);
1308
1308
  });
1309
1309
  this.channel.onmessage = ({ data }) => {
1310
- const { paths, trees } = noticeOf(data);
1310
+ const { paths, trees, outside } = noticeOf(data);
1311
1311
  for (const path of [...paths, ...trees]) this.forget(normalizePath(path));
1312
- remote?.emit({ paths, trees });
1312
+ const tell = () => remote?.emit({ paths, trees });
1313
+ if (!outside) tell();
1314
+ else void this.noticed(paths.map(normalizePath), Date.now()).finally(tell);
1313
1315
  };
1314
1316
  this.channel.unref?.();
1315
1317
  }
@@ -1768,6 +1770,14 @@ var OpfsFs = class {
1768
1770
  this.fileTimes.set(target, Date.now());
1769
1771
  this.scheduleFileTimes();
1770
1772
  }
1773
+ async noticed(paths, at) {
1774
+ for (const path of new Set(paths)) {
1775
+ const st = await this.lstat(path).catch(() => void 0);
1776
+ if (!st?.isFile || st.mtime.getTime() >= at) continue;
1777
+ this.fileTimes.set(path, Math.max(at, this.fileTimes.get(path) ?? 0));
1778
+ }
1779
+ this.scheduleFileTimes();
1780
+ }
1771
1781
  scheduleFileTimes() {
1772
1782
  if (this.flushing.file || this.fileTimes.size === 0) return;
1773
1783
  this.flushing.file = setTimeout(() => {
@@ -2427,8 +2437,8 @@ var OpfsFs = class {
2427
2437
  renamingDirs = /* @__PURE__ */ new Set();
2428
2438
  intents = 0;
2429
2439
  async intend(rename, at = `${RENAMES}/${crypto.randomUUID()}`) {
2430
- const record = { ...rename, at: Date.now() * 1e3 + this.intents++ % 1e3 };
2431
- await this.meta.update(at, () => ({ path: at, rename: record }));
2440
+ const record2 = { ...rename, at: Date.now() * 1e3 + this.intents++ % 1e3 };
2441
+ await this.meta.update(at, () => ({ path: at, rename: record2 }));
2432
2442
  return at;
2433
2443
  }
2434
2444
  async rollBack(from, to, intents) {
@@ -2939,7 +2949,7 @@ async function rootId(factory, root, locks = globalThis.navigator?.locks) {
2939
2949
  const all = await request(
2940
2950
  db.transaction(ROOTS_STORE, "readonly").objectStore(ROOTS_STORE).getAll()
2941
2951
  );
2942
- for (const record of all) if (await same(record.handle, root)) return record.id;
2952
+ for (const record2 of all) if (await same(record2.handle, root)) return record2.id;
2943
2953
  const id2 = crypto.randomUUID();
2944
2954
  if (await used(root)) await seed(factory, nameOf(id2));
2945
2955
  const tx = db.transaction(ROOTS_STORE, "readwrite");
@@ -4879,6 +4889,15 @@ function isHostname(name2) {
4879
4889
  function ownNames(hostname) {
4880
4890
  return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
4881
4891
  }
4892
+ function hostsFile(hostname = DEFAULT_HOSTNAME) {
4893
+ return [
4894
+ "127.0.0.1 localhost localhost.localdomain",
4895
+ "::1 localhost ip6-localhost",
4896
+ `${HOSTNAME_ADDRESS} ${ownNames(hostname).join(" ")}`,
4897
+ `${HOST_LOOPBACK_ADDRESS.join(".")} ${HOST_LOOPBACK}`,
4898
+ ""
4899
+ ].join("\n");
4900
+ }
4882
4901
 
4883
4902
  // src/kernel/net/routes.ts
4884
4903
  var HOST_ADDRESS = HOST_LOOPBACK_ADDRESS.join(".");
@@ -5563,6 +5582,7 @@ var LOCAL_ONLY = new Routes();
5563
5582
  var LoopbackNet = class {
5564
5583
  bound = /* @__PURE__ */ new Map();
5565
5584
  dgrams = /* @__PURE__ */ new Map();
5585
+ dgramServices = /* @__PURE__ */ new Map();
5566
5586
  unixDgrams = /* @__PURE__ */ new Map();
5567
5587
  activators = /* @__PURE__ */ new Map();
5568
5588
  internal = /* @__PURE__ */ new Set();
@@ -5613,9 +5633,16 @@ var LoopbackNet = class {
5613
5633
  releaseDgram(addr, socket) {
5614
5634
  if (this.dgrams.get(addr.port) === socket) this.dgrams.delete(addr.port);
5615
5635
  }
5616
- deliverDgram(port, datagram2) {
5636
+ serveDgram(port, serve) {
5637
+ this.dgramServices.set(port, serve);
5638
+ }
5639
+ deliverDgram(port, datagram2, to) {
5617
5640
  const target = this.dgrams.get(port);
5618
- return target ? target.deliver(datagram2) : false;
5641
+ if (target) return target.deliver(datagram2);
5642
+ const service = this.dgramServices.get(port);
5643
+ if (!service) return false;
5644
+ service(datagram2, to ?? { family: "inet", host: "127.0.0.1", port });
5645
+ return true;
5619
5646
  }
5620
5647
  bindable(addr, kernel) {
5621
5648
  if (addr.host !== "0.0.0.0" && !isLoopback(addr.host)) {
@@ -7098,7 +7125,7 @@ function satisfies(version, range2) {
7098
7125
  }
7099
7126
 
7100
7127
  // src/version.ts
7101
- var KERNEL_VERSION = true ? "1.136.9" : "0.0.0-dev";
7128
+ var KERNEL_VERSION = true ? "1.138.0" : "0.0.0-dev";
7102
7129
  var OS_RELEASE = "6.0.0-slicc";
7103
7130
  function procVersion() {
7104
7131
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -8616,11 +8643,11 @@ var CronService = class {
8616
8643
  }
8617
8644
  if (this.stopping.signal.aborted) return;
8618
8645
  const exit = ended.signal ? `signal=${ended.signal}` : `exit=${ended.status}`;
8619
- const header3 = encoder.encode(`--- ${iso} ${exit} missed=${missed} ---
8646
+ const header4 = encoder.encode(`--- ${iso} ${exit} missed=${missed} ---
8620
8647
  `);
8621
8648
  const body = output.bytes();
8622
8649
  const newline = body.length > 0 && body[body.length - 1] !== 10 ? encoder.encode("\n") : new Uint8Array();
8623
- await this.append(log, concat2([header3, body, newline]), account.uid, account.gid).catch(
8650
+ await this.append(log, concat2([header4, body, newline]), account.uid, account.gid).catch(
8624
8651
  (err) => this.error(messageOf(err))
8625
8652
  );
8626
8653
  }
@@ -9428,8 +9455,8 @@ var FileWatches = class {
9428
9455
  live = /* @__PURE__ */ new Set();
9429
9456
  local;
9430
9457
  remote;
9431
- constructor(local, remote) {
9432
- this.local = local;
9458
+ constructor(local2, remote) {
9459
+ this.local = local2;
9433
9460
  this.remote = remote;
9434
9461
  }
9435
9462
  announce() {
@@ -13149,18 +13176,18 @@ var SAB_I_ASYNC = 14;
13149
13176
  var SAB_I_STOP = 15;
13150
13177
  var SAB_I_BLOCKED = 16;
13151
13178
  var SAB_I_BLOCKED_HI = 17;
13152
- function loadBlocked(header3) {
13153
- return [Atomics.load(header3, SAB_I_BLOCKED), Atomics.load(header3, SAB_I_BLOCKED_HI)];
13179
+ function loadBlocked(header4) {
13180
+ return [Atomics.load(header4, SAB_I_BLOCKED), Atomics.load(header4, SAB_I_BLOCKED_HI)];
13154
13181
  }
13155
- function storeBlocked(header3, [low, high]) {
13156
- Atomics.store(header3, SAB_I_BLOCKED_HI, high);
13157
- Atomics.store(header3, SAB_I_BLOCKED, low);
13182
+ function storeBlocked(header4, [low, high]) {
13183
+ Atomics.store(header4, SAB_I_BLOCKED_HI, high);
13184
+ Atomics.store(header4, SAB_I_BLOCKED, low);
13158
13185
  }
13159
13186
  var anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
13160
13187
  var U32 = 2 ** 32;
13161
- function storeU53(header3, lo, hi, value2) {
13162
- Atomics.store(header3, hi, Math.floor(value2 / U32));
13163
- Atomics.store(header3, lo, value2 % U32 | 0);
13188
+ function storeU53(header4, lo, hi, value2) {
13189
+ Atomics.store(header4, hi, Math.floor(value2 / U32));
13190
+ Atomics.store(header4, lo, value2 % U32 | 0);
13164
13191
  }
13165
13192
  var SAB_STATE_READY = 2;
13166
13193
  var SAB_STATUS_BYTES = 1;
@@ -13209,7 +13236,7 @@ function sabViews(sab) {
13209
13236
  var PENDING_TTL_MS = SYNC_FS_REQUEST_TIMEOUT_MS + 5e3;
13210
13237
  function attachSyncSabResponder(port, sab, token, opts) {
13211
13238
  const views = sabViews(sab);
13212
- const { header: header3, window } = views;
13239
+ const { header: header4, window } = views;
13213
13240
  const pending = /* @__PURE__ */ new Map();
13214
13241
  let disposed = false;
13215
13242
  const { dispatch: dispatch2 } = opts;
@@ -13220,20 +13247,20 @@ function attachSyncSabResponder(port, sab, token, opts) {
13220
13247
  pending.delete(id2);
13221
13248
  }
13222
13249
  function publish(id2, entry, offset) {
13223
- if (Atomics.load(header3, SAB_I_REQ) !== id2) {
13250
+ if (Atomics.load(header4, SAB_I_REQ) !== id2) {
13224
13251
  drop(id2);
13225
13252
  return;
13226
13253
  }
13227
13254
  const chunk2 = Math.min(window.byteLength, entry.payload.byteLength - offset);
13228
13255
  if (chunk2 > 0) window.set(entry.payload.subarray(offset, offset + chunk2));
13229
- Atomics.store(header3, SAB_I_STATUS, entry.status);
13230
- storeU53(header3, SAB_I_TOTAL, SAB_I_TOTAL_HI, entry.payload.byteLength);
13231
- Atomics.store(header3, SAB_I_CHUNK, chunk2);
13232
- storeU53(header3, SAB_I_OFFSET, SAB_I_OFFSET_HI, offset);
13233
- Atomics.store(header3, SAB_I_SEQ, id2);
13234
- Atomics.store(header3, SAB_I_STATE, SAB_STATE_READY);
13235
- Atomics.add(header3, SAB_I_PUB, 1);
13236
- Atomics.notify(header3, SAB_I_PUB);
13256
+ Atomics.store(header4, SAB_I_STATUS, entry.status);
13257
+ storeU53(header4, SAB_I_TOTAL, SAB_I_TOTAL_HI, entry.payload.byteLength);
13258
+ Atomics.store(header4, SAB_I_CHUNK, chunk2);
13259
+ storeU53(header4, SAB_I_OFFSET, SAB_I_OFFSET_HI, offset);
13260
+ Atomics.store(header4, SAB_I_SEQ, id2);
13261
+ Atomics.store(header4, SAB_I_STATE, SAB_STATE_READY);
13262
+ Atomics.add(header4, SAB_I_PUB, 1);
13263
+ Atomics.notify(header4, SAB_I_PUB);
13237
13264
  if (offset + chunk2 >= entry.payload.byteLength) drop(id2);
13238
13265
  else if (entry.timer) {
13239
13266
  clearTimeout(entry.timer);
@@ -13448,6 +13475,15 @@ var ProcessClocks = class {
13448
13475
  }
13449
13476
  };
13450
13477
 
13478
+ // src/kernel/proc-info.ts
13479
+ function mayTrace(viewer, target) {
13480
+ const by = viewer?.cred;
13481
+ const of = target.cred;
13482
+ if (!by || !of || by.euid === 0) return true;
13483
+ const uid = of.ruid === by.euid && of.euid === by.euid && of.suid === by.euid;
13484
+ return uid && of.rgid === by.egid && of.egid === by.egid && of.sgid === by.egid;
13485
+ }
13486
+
13451
13487
  // src/fs/pages.ts
13452
13488
  var PAGE = 64 * 1024;
13453
13489
  var READAHEAD = 1024 * 1024;
@@ -14003,7 +14039,16 @@ var ProcTree = class {
14003
14039
  if (!/^[1-9]\d*$/.test(top) || !this.alive(Number(top))) return void 0;
14004
14040
  if (leaf === "task") return this.task(Number(top), rest2);
14005
14041
  if (rest2.length > 0) return void 0;
14006
- if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES, "task"] };
14042
+ if (leaf === void 0) {
14043
+ const exe = () => this.info(Number(top))?.exe === void 0 ? [] : ["exe"];
14044
+ return { kind: "dir", names: () => [...PID_NAMES, ...exe(), "task"] };
14045
+ }
14046
+ if (leaf === "exe") {
14047
+ const info = this.info(Number(top));
14048
+ if (info?.exe === void 0) return void 0;
14049
+ const denied2 = !mayTrace(this.ownInfo(), info);
14050
+ return { kind: "link", target: info.exe, ...denied2 ? { denied: denied2 } : {} };
14051
+ }
14007
14052
  if (!PID_NAMES.includes(leaf)) return void 0;
14008
14053
  return {
14009
14054
  kind: "file",
@@ -14015,6 +14060,10 @@ var ProcTree = class {
14015
14060
  }
14016
14061
  };
14017
14062
  }
14063
+ ownInfo() {
14064
+ const processes2 = this.listing().processes;
14065
+ return processes2.find((p) => p.tid === this.pid) ?? processes2.find((p) => p.pid === this.pid);
14066
+ }
14018
14067
  info(pid) {
14019
14068
  return this.listing().processes.find((p) => p.pid === pid);
14020
14069
  }
@@ -14078,6 +14127,7 @@ var ProcTree = class {
14078
14127
  readlink(path) {
14079
14128
  const node = this.find(path, false);
14080
14129
  if (node.kind !== "link") throw syncError("EINVAL", path);
14130
+ if (node.denied) throw syncError("EACCES", path);
14081
14131
  return node.target;
14082
14132
  }
14083
14133
  exists(path) {
@@ -15482,8 +15532,8 @@ function sameCert(a, b) {
15482
15532
  if (!a || !b) return a === b;
15483
15533
  return a.cert.length === b.cert.length && a.cert.every((byte, i) => byte === b.cert[i]);
15484
15534
  }
15485
- function winner(current, expected, record) {
15486
- return sameCert(current, expected) ? record : current;
15535
+ function winner(current, expected, record2) {
15536
+ return sameCert(current, expected) ? record2 : current;
15487
15537
  }
15488
15538
  var DAY = 24 * 60 * 60 * 1e3;
15489
15539
  var CA_LIFETIME = 3650 * DAY;
@@ -15516,15 +15566,15 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
15516
15566
  const store = (await open2()).transaction("ca").objectStore("ca");
15517
15567
  return await request2(store.get(owner));
15518
15568
  },
15519
- async swap(owner, expected, record) {
15569
+ async swap(owner, expected, record2) {
15520
15570
  const tx = (await open2()).transaction("ca", "readwrite");
15521
15571
  const store = tx.objectStore("ca");
15522
- let stored = record;
15572
+ let stored = record2;
15523
15573
  const read = store.get(owner);
15524
15574
  read.onsuccess = () => {
15525
15575
  const current = read.result;
15526
- const kept = winner(current, expected, record);
15527
- if (kept === record) store.put(record, owner);
15576
+ const kept = winner(current, expected, record2);
15577
+ if (kept === record2) store.put(record2, owner);
15528
15578
  else stored = kept;
15529
15579
  };
15530
15580
  await new Promise((resolve2, reject) => {
@@ -15544,14 +15594,14 @@ function validLeafName(host) {
15544
15594
  }
15545
15595
  var RealmCa = class _RealmCa {
15546
15596
  record;
15547
- constructor(record) {
15548
- this.record = record;
15597
+ constructor(record2) {
15598
+ this.record = record2;
15549
15599
  }
15550
15600
  static async open(owner, store, now = Date.now()) {
15551
15601
  const stored = await store.get(owner).catch(() => void 0);
15552
15602
  if (stored && stored.notAfter - now > CA_RENEW_BEFORE) return new _RealmCa(stored);
15553
- const record = await _RealmCa.create(owner, now);
15554
- return new _RealmCa(await store.swap(owner, stored, record));
15603
+ const record2 = await _RealmCa.create(owner, now);
15604
+ return new _RealmCa(await store.swap(owner, stored, record2));
15555
15605
  }
15556
15606
  static async create(owner, now) {
15557
15607
  const pair = await crypto.subtle.generateKey(ECDSA, false, ["sign", "verify"]);
@@ -15710,10 +15760,15 @@ var TlsEngine = class {
15710
15760
  const m = this.clientModule();
15711
15761
  if (servername.includes("\0")) throw new TlsError(-3, "tls engine: a server name has no NUL");
15712
15762
  const wire = alpnWire(alpn);
15713
- const name2 = this.put(new TextEncoder().encode(servername));
15763
+ const bytes = new TextEncoder().encode(servername);
15764
+ const name2 = this.put(bytes);
15714
15765
  try {
15715
15766
  const at = store?.ptr ?? 0;
15716
- const ptr = this.withBytes(wire, (p) => m._tls_client_new(at, name2, p, wire.length, flags2));
15767
+ const named = m._tls_client_new_name;
15768
+ const ptr = this.withBytes(
15769
+ wire,
15770
+ (p) => named ? named(at, name2, bytes.length, p, wire.length, flags2) : m._tls_client_new(at, name2, p, wire.length, flags2)
15771
+ );
15717
15772
  if (!ptr) throw this.error(m._tls_last_error(), "tls client");
15718
15773
  return new TlsSession(this, m, ptr);
15719
15774
  } finally {
@@ -16082,8 +16137,8 @@ function memoryCaStore() {
16082
16137
  const records = /* @__PURE__ */ new Map();
16083
16138
  return {
16084
16139
  get: async (owner) => records.get(owner),
16085
- swap: async (owner, expected, record) => {
16086
- const kept = winner(records.get(owner), expected, record);
16140
+ swap: async (owner, expected, record2) => {
16141
+ const kept = winner(records.get(owner), expected, record2);
16087
16142
  records.set(owner, kept);
16088
16143
  return kept;
16089
16144
  }
@@ -16213,10 +16268,10 @@ var WsHandles = class {
16213
16268
  open = /* @__PURE__ */ new Map();
16214
16269
  next;
16215
16270
  local;
16216
- constructor(transport, next3, local) {
16271
+ constructor(transport, next3, local2) {
16217
16272
  this.transport = transport;
16218
16273
  this.next = next3;
16219
- this.local = local;
16274
+ this.local = local2;
16220
16275
  }
16221
16276
  owns(handle) {
16222
16277
  return this.open.has(handle);
@@ -16245,8 +16300,8 @@ var WsHandles = class {
16245
16300
  return { ok: true, kind: "json", json: handle };
16246
16301
  }
16247
16302
  async connect(handle, req, entry) {
16248
- const { transport, local } = this;
16249
- const port = local?.port(req.url);
16303
+ const { transport, local: local2 } = this;
16304
+ const port = local2?.port(req.url);
16250
16305
  const open2 = { protocols: req.protocols, headers: req.headers, signal: entry.abort.signal };
16251
16306
  if (port === void 0 && (!transport.traits.websocket || !transport.websocket)) {
16252
16307
  return fail("ENOTSUP", NO_WEBSOCKET2);
@@ -16256,7 +16311,7 @@ var WsHandles = class {
16256
16311
  socket = port === void 0 ? await transport.websocket({
16257
16312
  url: toHostLoopback(req.url),
16258
16313
  ...open2
16259
- }) : await local.websocket({ url: req.url, ...open2 }, port);
16314
+ }) : await local2.websocket({ url: req.url, ...open2 }, port);
16260
16315
  } catch (e) {
16261
16316
  return fail(errnoOf(e), message(e));
16262
16317
  }
@@ -16387,11 +16442,11 @@ var HttpHandles = class {
16387
16442
  ws;
16388
16443
  owner;
16389
16444
  local;
16390
- constructor(transport, owner, local) {
16445
+ constructor(transport, owner, local2) {
16391
16446
  this.transport = transport;
16392
16447
  this.owner = owner;
16393
- this.local = local;
16394
- this.ws = new WsHandles(transport, () => ++this.nextHandle, local);
16448
+ this.local = local2;
16449
+ this.ws = new WsHandles(transport, () => ++this.nextHandle, local2);
16395
16450
  }
16396
16451
  syscall(req) {
16397
16452
  if (req.op.startsWith("net-ws-")) return this.ws.syscall(req);
@@ -16543,6 +16598,43 @@ var HttpHandles = class {
16543
16598
  }
16544
16599
  };
16545
16600
 
16601
+ // src/kernel/net/hosts-file.ts
16602
+ var HOSTS_PATH = "/etc/hosts";
16603
+ function parseHosts(text) {
16604
+ const table = /* @__PURE__ */ new Map();
16605
+ for (const raw2 of text.split("\n")) {
16606
+ const [address, ...names2] = raw2.replace(/#.*/, "").trim().split(/\s+/);
16607
+ if (!address || names2.length === 0) continue;
16608
+ if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
16609
+ for (const name2 of names2) {
16610
+ const key = name2.toLowerCase().replace(/\.$/, "");
16611
+ const known = table.get(key) ?? [];
16612
+ if (!known.includes(address)) known.push(address);
16613
+ table.set(key, known);
16614
+ }
16615
+ }
16616
+ return table;
16617
+ }
16618
+ function hostsReader(fs, path = HOSTS_PATH) {
16619
+ let stamp = "";
16620
+ let table;
16621
+ return async () => {
16622
+ const st = await fs.stat(path).catch(() => void 0);
16623
+ if (!st?.isFile) {
16624
+ stamp = "";
16625
+ table = void 0;
16626
+ return void 0;
16627
+ }
16628
+ const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
16629
+ if (now === stamp && table) return table;
16630
+ const text = await fs.readFile(path).catch(() => void 0);
16631
+ if (text === void 0) return void 0;
16632
+ stamp = now;
16633
+ table = parseHosts(text);
16634
+ return table;
16635
+ };
16636
+ }
16637
+
16546
16638
  // src/kernel/net/uplink.ts
16547
16639
  function carriesUdp(uplink) {
16548
16640
  return uplink.traits.udp === true && typeof uplink.udp === "function";
@@ -16559,13 +16651,15 @@ var NEVER = new Routes(true);
16559
16651
  var RemoteUplink = class {
16560
16652
  traits;
16561
16653
  routes;
16654
+ nameserver;
16562
16655
  port;
16563
16656
  waiting = /* @__PURE__ */ new Map();
16564
16657
  nextId = 0;
16565
- constructor(port, traits, routes) {
16658
+ constructor(port, traits, routes, nameserver) {
16566
16659
  this.port = port;
16567
16660
  this.traits = traits;
16568
16661
  this.routes = routes;
16662
+ this.nameserver = nameserver;
16569
16663
  }
16570
16664
  receive(reply) {
16571
16665
  const waiter = this.waiting.get(reply.uid);
@@ -16688,6 +16782,7 @@ var Resolver = class {
16688
16782
  timeoutMs;
16689
16783
  log;
16690
16784
  own;
16785
+ builtin;
16691
16786
  cache = /* @__PURE__ */ new Map();
16692
16787
  pending = /* @__PURE__ */ new Map();
16693
16788
  hosts;
@@ -16698,6 +16793,7 @@ var Resolver = class {
16698
16793
  this.timeoutMs = options.timeoutMs ?? RESOLVE_TIMEOUT_MS;
16699
16794
  this.log = options.log ?? ((message3) => console.warn(message3));
16700
16795
  this.own = ownNames(options.hostname ?? DEFAULT_HOSTNAME);
16796
+ this.builtin = parseHosts(hostsFile(options.hostname ?? DEFAULT_HOSTNAME));
16701
16797
  this.hosts = options.hosts;
16702
16798
  }
16703
16799
  async fromFile(key, family) {
@@ -16707,18 +16803,34 @@ var Resolver = class {
16707
16803
  const v6 = listed.filter((a) => ipv4Bytes(a) === void 0);
16708
16804
  return family === 4 ? v4 : family === 6 ? v6 : [...v4, ...v6];
16709
16805
  }
16806
+ async known(name2) {
16807
+ const key = name2.toLowerCase().replace(/\.$/, "");
16808
+ if (ipv4Bytes(key) || ipv6Groups(key)) return false;
16809
+ if (hostsEntry(key, this.own) !== void 0) return true;
16810
+ return ((await this.hosts?.().catch(() => void 0))?.get(key)?.length ?? 0) > 0;
16811
+ }
16812
+ async reverse(address) {
16813
+ const v6 = ipv6Groups(address)?.join(":");
16814
+ const same3 = (a) => a === address || v6 !== void 0 && ipv6Groups(a)?.join(":") === v6;
16815
+ const file = await this.hosts?.().catch(() => void 0);
16816
+ for (const table of [file, this.builtin]) {
16817
+ for (const [name2, addresses] of table ?? []) if (addresses.some(same3)) return name2;
16818
+ }
16819
+ if (ipv4Bytes(address)?.[0] === 127) return "localhost";
16820
+ return void 0;
16821
+ }
16710
16822
  async resolve(name2, family, blocking) {
16711
16823
  const key = name2.toLowerCase().replace(/\.$/, "");
16712
- const local = hostsEntry(key, this.own);
16824
+ const local2 = hostsEntry(key, this.own);
16713
16825
  if (ipv6Groups(key)) {
16714
- const v4 = family !== 6 && local ? [local] : [];
16826
+ const v4 = family !== 6 && local2 ? [local2] : [];
16715
16827
  return family === 4 ? v4 : [...v4, key];
16716
16828
  }
16717
16829
  const listed = this.hosts ? await this.fromFile(key, family) : void 0;
16718
16830
  if (listed?.length) return listed;
16719
- if (local) {
16831
+ if (local2) {
16720
16832
  const six = loopbackName(key, this.own) ? ["::1"] : [];
16721
- return family === 6 ? six : family === 4 ? [local] : [local, ...six];
16833
+ return family === 6 ? six : family === 4 ? [local2] : [local2, ...six];
16722
16834
  }
16723
16835
  if (!this.uplink || key === "") return [];
16724
16836
  const asked = this.uplink.traits.ipv6 ? family : 4;
@@ -17757,14 +17869,15 @@ var KernelDgram = class {
17757
17869
  const max = familyOf(target.host) === 6 ? MAX_DATAGRAM_V6 : MAX_DATAGRAM_V4;
17758
17870
  if (bytes.length > max) throw new KernelError("EMSGSIZE");
17759
17871
  const where = this.route(target.host);
17760
- const local = this.bound();
17872
+ const local2 = this.bound();
17761
17873
  if (where === "uplink") return this.sendUp(bytes, target);
17762
17874
  const from = {
17763
17875
  family: "inet",
17764
- host: local.host === "0.0.0.0" ? "127.0.0.1" : local.host,
17765
- port: local.port
17876
+ host: local2.host === "0.0.0.0" ? "127.0.0.1" : local2.host,
17877
+ port: local2.port
17766
17878
  };
17767
- const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from });
17879
+ const dest = { family: "inet", host: canonicalHost(target.host), port: target.port };
17880
+ const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from }, dest);
17768
17881
  if (!delivered && this.peer && sameAddr(this.peer, target)) {
17769
17882
  this.pending = "ECONNREFUSED";
17770
17883
  this.changes.wake();
@@ -19361,8 +19474,8 @@ function clientFirstOf(message3) {
19361
19474
  return m ? { header: m[1], bare: m[2] } : void 0;
19362
19475
  }
19363
19476
  var latinBytes = (text) => Uint8Array.from(text, (c) => c.charCodeAt(0));
19364
- function channelOf(header3, binding) {
19365
- const head = latinBytes(header3);
19477
+ function channelOf(header4, binding) {
19478
+ const head = latinBytes(header4);
19366
19479
  const all = new Uint8Array(head.length + (binding?.length ?? 0));
19367
19480
  all.set(head);
19368
19481
  if (binding) all.set(binding, head.length);
@@ -19587,8 +19700,8 @@ function frame3(type, body) {
19587
19700
  return out;
19588
19701
  }
19589
19702
  function pgLength(bytes, started) {
19590
- const header3 = started ? 5 : 4;
19591
- if (bytes.length < header3) return void 0;
19703
+ const header4 = started ? 5 : 4;
19704
+ if (bytes.length < header4) return void 0;
19592
19705
  const length2 = int32(bytes, started ? 1 : 0);
19593
19706
  return started ? 1 + length2 : length2;
19594
19707
  }
@@ -19616,16 +19729,16 @@ function initial(message3) {
19616
19729
  function int32Text(n) {
19617
19730
  return String.fromCharCode(n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255);
19618
19731
  }
19619
- function serverHeader(header3, server) {
19620
- if (header3 === "n,,") return header3;
19621
- if (header3 === "y,," && !server.plus) return header3;
19622
- if (header3 === END_POINT && server.binding) return header3;
19732
+ function serverHeader(header4, server) {
19733
+ if (header4 === "n,,") return header4;
19734
+ if (header4 === "y,," && !server.plus) return header4;
19735
+ if (header4 === END_POINT && server.binding) return header4;
19623
19736
  return server.plus && server.binding ? END_POINT : "n,,";
19624
19737
  }
19625
- function rewritten(first, header3) {
19738
+ function rewritten(first, header4) {
19626
19739
  const parsed2 = clientFirstOf(first.data);
19627
- if (!parsed2 || parsed2.header === header3) return first;
19628
- return { mechanism: header3 === END_POINT ? PLUS : PLAIN, data: `${header3}${parsed2.bare}` };
19740
+ if (!parsed2 || parsed2.header === header4) return first;
19741
+ return { mechanism: header4 === END_POINT ? PLUS : PLAIN, data: `${header4}${parsed2.bare}` };
19629
19742
  }
19630
19743
  var PgClient = class {
19631
19744
  clientFirst;
@@ -20750,8 +20863,8 @@ async function datagram(req, proc) {
20750
20863
  const ready2 = pollFile(dgram).readable;
20751
20864
  if (req.nonblock && !ready2) throw new KernelError("EAGAIN");
20752
20865
  const got = await dgram.receive(req.max, req.peek, ready2 ? void 0 : proc.blocking());
20753
- const { bytes, from, truncated } = got;
20754
- return { ok: true, kind: "bytes", bytes: encodeReceived({ bytes, truncated, ...from }) };
20866
+ const { bytes, from, truncated: truncated2 } = got;
20867
+ return { ok: true, kind: "bytes", bytes: encodeReceived({ bytes, truncated: truncated2, ...from }) };
20755
20868
  }
20756
20869
  async function unixDatagram(req, dgram, proc) {
20757
20870
  if (req.op === "sock-sendto") {
@@ -20761,11 +20874,11 @@ async function unixDatagram(req, dgram, proc) {
20761
20874
  const ready2 = pollFile(dgram).readable;
20762
20875
  if (req.nonblock && !ready2) throw new KernelError("EAGAIN");
20763
20876
  const got = await dgram.receive(req.max, req.peek, ready2 ? void 0 : proc.blocking());
20764
- const { bytes, from, truncated } = got;
20877
+ const { bytes, from, truncated: truncated2 } = got;
20765
20878
  return {
20766
20879
  ok: true,
20767
20880
  kind: "bytes",
20768
- bytes: encodeReceived({ bytes, truncated, host: from.path, port: 0, unix: true })
20881
+ bytes: encodeReceived({ bytes, truncated: truncated2, host: from.path, port: 0, unix: true })
20769
20882
  };
20770
20883
  }
20771
20884
  function domainOf(socket) {
@@ -23516,9 +23629,9 @@ var JsThreads = class {
23516
23629
  const { control, port } = msg;
23517
23630
  const tid = ++this.last;
23518
23631
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
23519
- const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
23632
+ const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
23520
23633
  const owned4 = new SharedArrayBuffer(4 * (1 + JS_THREAD_OWNED_FDS));
23521
- if (this.frozen) Atomics.store(header3, SAB_I_STOP, 1);
23634
+ if (this.frozen) Atomics.store(header4, SAB_I_STOP, 1);
23522
23635
  const clock = this.deps.clocks.thread(tid + 1, sab);
23523
23636
  let ended = false;
23524
23637
  const end = (code) => {
@@ -23526,7 +23639,7 @@ var JsThreads = class {
23526
23639
  ended = true;
23527
23640
  this.live.delete(tid);
23528
23641
  this.headers.delete(tid);
23529
- this.deps.wakes.delete(header3);
23642
+ this.deps.wakes.delete(header4);
23530
23643
  for (const [id2, token] of ops) {
23531
23644
  void this.deps.dispatch({ op: "async-cancel", id: id2, token });
23532
23645
  }
@@ -23576,8 +23689,8 @@ var JsThreads = class {
23576
23689
  control.addEventListener("message", onControl);
23577
23690
  control.start();
23578
23691
  this.live.set(tid, end);
23579
- this.headers.set(tid, header3);
23580
- this.deps.wakes.add(header3);
23692
+ this.headers.set(tid, header4);
23693
+ this.deps.wakes.add(header4);
23581
23694
  const init = {
23582
23695
  ...this.deps.init(sab, lane.lane),
23583
23696
  type: JS_THREAD_INIT,
@@ -23597,9 +23710,9 @@ var JsThreads = class {
23597
23710
  }
23598
23711
  stopped(stopped) {
23599
23712
  this.frozen = stopped;
23600
- for (const header3 of this.headers.values()) {
23601
- Atomics.store(header3, SAB_I_STOP, stopped ? 1 : 0);
23602
- Atomics.notify(header3, SAB_I_STOP);
23713
+ for (const header4 of this.headers.values()) {
23714
+ Atomics.store(header4, SAB_I_STOP, stopped ? 1 : 0);
23715
+ Atomics.notify(header4, SAB_I_STOP);
23603
23716
  }
23604
23717
  }
23605
23718
  close() {
@@ -23644,13 +23757,13 @@ var Dying = class {
23644
23757
  hard;
23645
23758
  busy = 0;
23646
23759
  finish;
23647
- start(code, sig, header3, process, finish) {
23760
+ start(code, sig, header4, process, finish) {
23648
23761
  if (this.ending) return;
23649
23762
  this.ending = { code, sig };
23650
23763
  this.finish = finish;
23651
23764
  this.hard = setTimeout(finish, KILL_HARD_MS);
23652
23765
  this.arm();
23653
- Atomics.store(header3, SAB_I_KILLED, code);
23766
+ Atomics.store(header4, SAB_I_KILLED, code);
23654
23767
  process.die();
23655
23768
  }
23656
23769
  serve(req, work) {
@@ -23697,8 +23810,8 @@ function unblockedThread(threads, sig) {
23697
23810
  }
23698
23811
  return void 0;
23699
23812
  }
23700
- function unblocked(header3) {
23701
- return Atomics.load(header3, SAB_I_SIGNALS) & ~Atomics.load(header3, SAB_I_BLOCKED);
23813
+ function unblocked(header4) {
23814
+ return Atomics.load(header4, SAB_I_SIGNALS) & ~Atomics.load(header4, SAB_I_BLOCKED);
23702
23815
  }
23703
23816
  function threadCall(process, req, cancelled, block) {
23704
23817
  return isWasmSyscall(req) ? process.syscall(req, cancelled, block) : dispatchSyncFs(req);
@@ -23710,24 +23823,24 @@ function threadCancel(thread) {
23710
23823
  return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
23711
23824
  }
23712
23825
  var asyncFanout = /* @__PURE__ */ new WeakMap();
23713
- function notifiers(header3) {
23826
+ function notifiers(header4) {
23714
23827
  return {
23715
23828
  onPending(sig) {
23716
- Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig));
23717
- Atomics.notify(header3, SAB_I_SIGNALS);
23829
+ Atomics.or(header4, SAB_I_SIGNALS, sigbit(sig));
23830
+ Atomics.notify(header4, SAB_I_SIGNALS);
23718
23831
  },
23719
23832
  onAsync() {
23720
- for (const at of [header3, ...asyncFanout.get(header3) ?? []]) {
23833
+ for (const at of [header4, ...asyncFanout.get(header4) ?? []]) {
23721
23834
  Atomics.add(at, SAB_I_ASYNC, 1);
23722
23835
  Atomics.notify(at, SAB_I_ASYNC);
23723
23836
  }
23724
23837
  }
23725
23838
  };
23726
23839
  }
23727
- function publishStops(process, header3) {
23840
+ function publishStops(process, header4) {
23728
23841
  process.onState((state) => {
23729
- Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
23730
- Atomics.notify(header3, SAB_I_STOP);
23842
+ Atomics.store(header4, SAB_I_STOP, state === "stopped" ? 1 : 0);
23843
+ Atomics.notify(header4, SAB_I_STOP);
23731
23844
  });
23732
23845
  }
23733
23846
  function transferOf(opts, lane) {
@@ -23819,7 +23932,7 @@ function linksOf(opts) {
23819
23932
  function clipboardName(opts) {
23820
23933
  return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
23821
23934
  }
23822
- function processOptions(opts, header3, hooks, created4) {
23935
+ function processOptions(opts, header4, hooks, created4) {
23823
23936
  return {
23824
23937
  ...inherited(opts),
23825
23938
  ...opts.owners ? { owners: true } : {},
@@ -23858,16 +23971,16 @@ function processOptions(opts, header3, hooks, created4) {
23858
23971
  watches: opts.watches,
23859
23972
  onReap: opts.onReap,
23860
23973
  resolver: opts.resolver,
23861
- ...notifiers(header3),
23862
- onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
23863
- hasPending: () => unblocked(header3) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
23974
+ ...notifiers(header4),
23975
+ onTimer: (which) => void Atomics.or(header4, SAB_I_TIMERS, 1 << which),
23976
+ hasPending: () => unblocked(header4) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
23864
23977
  raise: hooks.raise,
23865
23978
  threadKill: hooks.threadKill,
23866
23979
  unblockedThread: hooks.unblockedThread,
23867
23980
  ...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
23868
23981
  ...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
23869
- ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {},
23870
- ...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header3, SAB_I_BLOCKED) } : {}
23982
+ ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {},
23983
+ ...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header4, SAB_I_BLOCKED) } : {}
23871
23984
  };
23872
23985
  }
23873
23986
  function threadInit(opts, program, sab, cred, thread, main) {
@@ -23933,9 +24046,9 @@ async function crashReport(process, onError, message3) {
23933
24046
  function spawnWasmProcess(opts) {
23934
24047
  const { promise: ready2, resolve: started } = readiness(opts.program.abi);
23935
24048
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
23936
- const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
24049
+ const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
23937
24050
  const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
23938
- if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header3, blocked2);
24051
+ if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header4, blocked2);
23939
24052
  const threadSignals = /* @__PURE__ */ new Map();
23940
24053
  const created4 = new Created();
23941
24054
  const process = new WasmProcess(
@@ -23943,7 +24056,7 @@ function spawnWasmProcess(opts) {
23943
24056
  opts.fds,
23944
24057
  processOptions(
23945
24058
  opts,
23946
- header3,
24059
+ header4,
23947
24060
  {
23948
24061
  raise: (sig, info) => signal(sig, info),
23949
24062
  threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig),
@@ -23956,7 +24069,7 @@ function spawnWasmProcess(opts) {
23956
24069
  created4
23957
24070
  )
23958
24071
  );
23959
- publishStops(process, header3);
24072
+ publishStops(process, header4);
23960
24073
  const holds2 = new HeldPaths();
23961
24074
  opts.held?.add(holds2);
23962
24075
  const token = holdingToken(opts, holds2, {
@@ -23977,7 +24090,7 @@ function spawnWasmProcess(opts) {
23977
24090
  dispatch: clocks.timed(void 0, dispatch2)
23978
24091
  });
23979
24092
  const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
23980
- const jsThreads = jsThreadsOf(opts, process, token, dispatch2, clocks, header3);
24093
+ const jsThreads = jsThreadsOf(opts, process, token, dispatch2, clocks, header4);
23981
24094
  const { promise: exited, resolve: settle3 } = Promise.withResolvers();
23982
24095
  let done5 = false;
23983
24096
  const crash = new CrashSlot((message3) => crashReport(process, opts.onError, message3));
@@ -24076,7 +24189,7 @@ function spawnWasmProcess(opts) {
24076
24189
  );
24077
24190
  const terminate = (code, sig) => {
24078
24191
  if (opts.program.abi !== "wasi" || done5) finish(code, sig);
24079
- else dying.start(code, sig, header3, process, () => finish(code, sig));
24192
+ else dying.start(code, sig, header4, process, () => finish(code, sig));
24080
24193
  };
24081
24194
  const signal = (sig, info) => {
24082
24195
  if (process.signal(sig, info) === "terminate")
@@ -24091,16 +24204,16 @@ function spawnWasmProcess(opts) {
24091
24204
  signal,
24092
24205
  termsig: () => endedBy,
24093
24206
  onState: (listener) => process.onState(listener),
24094
- memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
24095
- ...processViews(process, opts, header3),
24207
+ memory: () => Atomics.load(header4, SAB_I_MEMORY) * 65536,
24208
+ ...processViews(process, opts, header4),
24096
24209
  writesBack: () => opts.program.abi === "wasi" && !done5,
24097
24210
  ...clockViews(clocks)
24098
24211
  };
24099
24212
  }
24100
- function jsThreadsOf(opts, process, token, dispatch2, clocks, header3) {
24213
+ function jsThreadsOf(opts, process, token, dispatch2, clocks, header4) {
24101
24214
  if (opts.program.abi !== "js") return void 0;
24102
24215
  const wakes = /* @__PURE__ */ new Set();
24103
- asyncFanout.set(header3, wakes);
24216
+ asyncFanout.set(header4, wakes);
24104
24217
  const threads = new JsThreads({
24105
24218
  wakes,
24106
24219
  cap: jsThreadCap(opts.env),
@@ -24115,10 +24228,10 @@ function jsThreadsOf(opts, process, token, dispatch2, clocks, header3) {
24115
24228
  process.onState((state) => threads.stopped(state === "stopped"));
24116
24229
  return threads;
24117
24230
  }
24118
- function processViews(process, opts, header3) {
24231
+ function processViews(process, opts, header4) {
24119
24232
  return {
24120
24233
  ignoredSignals: (fork) => process.inheritable(fork),
24121
- blockedSignals: () => opts.program.abi === "wasi" ? loadBlocked(header3) : [0, 0],
24234
+ blockedSignals: () => opts.program.abi === "wasi" ? loadBlocked(header4) : [0, 0],
24122
24235
  signalMasks: () => process.signalMasks(),
24123
24236
  umask: () => process.umask,
24124
24237
  cred: () => copyCred(process.cred)
@@ -24676,42 +24789,398 @@ function isMessage(data) {
24676
24789
  return adopt !== null && Array.isArray(adopt.records) && Array.isArray(adopt.flocks);
24677
24790
  }
24678
24791
 
24679
- // src/kernel/net/hosts-file.ts
24680
- var HOSTS_PATH = "/etc/hosts";
24681
- function parseHosts(text) {
24682
- const table = /* @__PURE__ */ new Map();
24683
- for (const raw2 of text.split("\n")) {
24684
- const [address, ...names2] = raw2.replace(/#.*/, "").trim().split(/\s+/);
24685
- if (!address || names2.length === 0) continue;
24686
- if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
24687
- for (const name2 of names2) {
24688
- const key = name2.toLowerCase().replace(/\.$/, "");
24689
- const known = table.get(key) ?? [];
24690
- if (!known.includes(address)) known.push(address);
24691
- table.set(key, known);
24792
+ // src/kernel/net/dns-stub.ts
24793
+ var DNS_PORT = 53;
24794
+ var DNS_STUB_ADDRESS = "127.0.0.53";
24795
+ var RESOLV_CONF_PATH = "/etc/resolv.conf";
24796
+ var RESOLV_CONF = `nameserver ${DNS_STUB_ADDRESS}
24797
+ options edns0
24798
+ `;
24799
+ var DNS_STUB_TTL = 30;
24800
+ var DNS_FORWARD_TIMEOUT_MS = 5e3;
24801
+ var DNS_TCP_IDLE_MS = 1e4;
24802
+ var DNS_TCP_MAX = 64;
24803
+ var DNS_UDP_INFLIGHT = 64;
24804
+ var TYPE_A = 1;
24805
+ var TYPE_PTR = 12;
24806
+ var TYPE_AAAA = 28;
24807
+ var TYPE_OPT = 41;
24808
+ var CLASS_IN = 1;
24809
+ var NOERROR = 0;
24810
+ var FORMERR = 1;
24811
+ var SERVFAIL = 2;
24812
+ var NXDOMAIN = 3;
24813
+ var NOTIMP = 4;
24814
+ var QR = 32768;
24815
+ var AA = 1024;
24816
+ var TC = 512;
24817
+ var RD = 256;
24818
+ var RA = 128;
24819
+ var CD = 16;
24820
+ var UDP_PLAIN = 512;
24821
+ var UDP_EDNS = 1232;
24822
+ var UDP_MAX = 4096;
24823
+ var DOH_MAX = 65535;
24824
+ var LOCAL_ZONES = ["localhost", "slicc.internal"];
24825
+ var MESSAGE = "application/dns-message";
24826
+ var u16 = (b, at) => b[at] << 8 | b[at + 1];
24827
+ function skipName(b, at) {
24828
+ let i = at;
24829
+ for (let hops = 0; hops < 128; hops++) {
24830
+ if (i >= b.length) return void 0;
24831
+ const len = b[i];
24832
+ if (len === 0) return i + 1;
24833
+ if ((len & 192) === 192) return i + 2 <= b.length ? i + 2 : void 0;
24834
+ if (len & 192) return void 0;
24835
+ i += len + 1;
24836
+ }
24837
+ return void 0;
24838
+ }
24839
+ function readName(b, at) {
24840
+ const labels = [];
24841
+ let i = at;
24842
+ let size = 0;
24843
+ for (; ; ) {
24844
+ if (i >= b.length) return void 0;
24845
+ const len = b[i];
24846
+ if (len === 0) break;
24847
+ if (len & 192) return void 0;
24848
+ size += len + 1;
24849
+ if (size > 254 || i + 1 + len > b.length) return void 0;
24850
+ labels.push(new TextDecoder().decode(b.subarray(i + 1, i + 1 + len)));
24851
+ i += len + 1;
24852
+ }
24853
+ return { name: labels.join(".").toLowerCase(), end: i + 1 };
24854
+ }
24855
+ function parseQuery(b) {
24856
+ if (b.length < 12) return void 0;
24857
+ const id2 = u16(b, 0);
24858
+ const flags2 = u16(b, 2);
24859
+ if (flags2 & QR) return void 0;
24860
+ if (flags2 >> 11 & 15) return { ok: false, id: id2, flags: flags2, rcode: NOTIMP };
24861
+ if (u16(b, 4) !== 1) return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24862
+ const read = readName(b, 12);
24863
+ if (!read || read.end + 4 > b.length) return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24864
+ const type = u16(b, read.end);
24865
+ const klass = u16(b, read.end + 2);
24866
+ const end = read.end + 4;
24867
+ let edns;
24868
+ let at = end;
24869
+ const records = u16(b, 6) + u16(b, 8) + u16(b, 10);
24870
+ for (let n = 0; n < records; n++) {
24871
+ const after = skipName(b, at);
24872
+ if (after === void 0 || after + 10 > b.length)
24873
+ return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24874
+ if (u16(b, after) === TYPE_OPT) edns = Math.max(UDP_PLAIN, u16(b, after + 2));
24875
+ at = after + 10 + u16(b, after + 8);
24876
+ if (at > b.length) return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24877
+ }
24878
+ return { ok: true, question: { id: id2, flags: flags2, name: read.name, type, klass, end, edns } };
24879
+ }
24880
+ function encodeName(name2) {
24881
+ const out = [];
24882
+ for (const label of name2.split(".").filter(Boolean)) {
24883
+ const bytes = new TextEncoder().encode(label);
24884
+ out.push(bytes.length, ...bytes);
24885
+ }
24886
+ out.push(0);
24887
+ return out;
24888
+ }
24889
+ function header2(id2, flags2, counts) {
24890
+ const out = [id2 >> 8, id2 & 255, flags2 >> 8, flags2 & 255];
24891
+ for (const c of counts) out.push(c >> 8, c & 255);
24892
+ return out;
24893
+ }
24894
+ function opt() {
24895
+ return [0, 0, TYPE_OPT, UDP_EDNS >> 8, UDP_EDNS & 255, 0, 0, 0, 0, 0, 0];
24896
+ }
24897
+ function record(type, rdata) {
24898
+ const ttl = DNS_STUB_TTL;
24899
+ return [
24900
+ 192,
24901
+ 12,
24902
+ type >> 8,
24903
+ type & 255,
24904
+ 0,
24905
+ CLASS_IN,
24906
+ ttl >>> 24 & 255,
24907
+ ttl >>> 16 & 255,
24908
+ ttl >>> 8 & 255,
24909
+ ttl & 255,
24910
+ rdata.length >> 8,
24911
+ rdata.length & 255,
24912
+ ...rdata
24913
+ ];
24914
+ }
24915
+ function replyFlags(query, rcode, aa) {
24916
+ return QR | query & 30720 | (aa ? AA : 0) | query & RD | RA | query & CD | rcode;
24917
+ }
24918
+ function answers(reply, q) {
24919
+ if (reply.length < 12 || !(u16(reply, 2) & QR) || u16(reply, 4) !== 1) return false;
24920
+ const read = readName(reply, 12);
24921
+ if (!read || read.end + 4 > reply.length) return false;
24922
+ return read.name === q.name && u16(reply, read.end) === q.type && u16(reply, read.end + 2) === q.klass;
24923
+ }
24924
+ function errorReply(id2, flags2, rcode) {
24925
+ return new Uint8Array(header2(id2, replyFlags(flags2, rcode, false), [0, 0, 0, 0]));
24926
+ }
24927
+ function answerReply(query, q, rcode, answers2, aa) {
24928
+ const extra = q.edns !== void 0 ? [opt()] : [];
24929
+ return new Uint8Array([
24930
+ ...header2(q.id, replyFlags(q.flags, rcode, aa), [1, answers2.length, 0, extra.length]),
24931
+ ...query.subarray(12, q.end),
24932
+ ...answers2.flat(),
24933
+ ...extra.flat()
24934
+ ]);
24935
+ }
24936
+ function truncated(reply, q, query) {
24937
+ const limit = q.edns !== void 0 ? Math.min(q.edns, UDP_MAX) : UDP_PLAIN;
24938
+ if (reply.length <= limit) return reply;
24939
+ const flags2 = u16(reply, 2) | TC;
24940
+ const extra = q.edns !== void 0 ? [opt()] : [];
24941
+ return new Uint8Array([
24942
+ ...header2(q.id, flags2, [1, 0, 0, extra.length]),
24943
+ ...query.subarray(12, q.end),
24944
+ ...extra.flat()
24945
+ ]);
24946
+ }
24947
+ function ipv6Text(groups) {
24948
+ return groups.map((g) => g.toString(16)).join(":");
24949
+ }
24950
+ function reverseAddress(name2) {
24951
+ if (name2.endsWith(".in-addr.arpa")) {
24952
+ const parts2 = name2.slice(0, -".in-addr.arpa".length).split(".");
24953
+ if (parts2.length !== 4) return void 0;
24954
+ const text = parts2.reverse().join(".");
24955
+ return ipv4Bytes(text) ? text.split(".").map(Number).join(".") : void 0;
24956
+ }
24957
+ if (name2.endsWith(".ip6.arpa")) {
24958
+ const nibbles = name2.slice(0, -".ip6.arpa".length).split(".");
24959
+ if (nibbles.length !== 32 || !nibbles.every((n) => /^[0-9a-f]$/.test(n))) return void 0;
24960
+ const hex4 = nibbles.reverse().join("");
24961
+ const groups = Array.from(
24962
+ { length: 8 },
24963
+ (_, i) => Number.parseInt(hex4.slice(i * 4, i * 4 + 4), 16)
24964
+ );
24965
+ return ipv6Text(groups);
24966
+ }
24967
+ return void 0;
24968
+ }
24969
+ function local(name2) {
24970
+ return LOCAL_ZONES.some((zone) => name2 === zone || name2.endsWith(`.${zone}`));
24971
+ }
24972
+ function literal(name2) {
24973
+ return ipv4Bytes(name2) !== void 0 || ipv6Groups(name2) !== void 0;
24974
+ }
24975
+ function addressData(address, type) {
24976
+ if (type === TYPE_A) return ipv4Bytes(address);
24977
+ const groups = type === TYPE_AAAA ? ipv6Groups(address) : void 0;
24978
+ return groups?.flatMap((g) => [g >> 8, g & 255]);
24979
+ }
24980
+ var DnsStub = class {
24981
+ resolver;
24982
+ forwarder;
24983
+ timeoutMs;
24984
+ constructor(options) {
24985
+ this.resolver = options.resolver;
24986
+ this.forwarder = options.forward;
24987
+ this.timeoutMs = options.timeoutMs ?? DNS_FORWARD_TIMEOUT_MS;
24988
+ }
24989
+ async answer(query, udp) {
24990
+ const parsed2 = parseQuery(query);
24991
+ if (!parsed2) return void 0;
24992
+ if (!parsed2.ok) return errorReply(parsed2.id, parsed2.flags, parsed2.rcode);
24993
+ const q = parsed2.question;
24994
+ const reply = await this.reply(query, q).catch(
24995
+ () => answerReply(query, q, SERVFAIL, [], false)
24996
+ );
24997
+ return udp ? truncated(reply, q, query) : reply;
24998
+ }
24999
+ async reply(query, q) {
25000
+ if (q.klass !== CLASS_IN || literal(q.name)) return this.forward(query, q);
25001
+ if (q.type === TYPE_PTR) {
25002
+ const address = reverseAddress(q.name);
25003
+ const name2 = address !== void 0 ? await this.reverse(address) : void 0;
25004
+ if (name2 !== void 0)
25005
+ return answerReply(query, q, NOERROR, [record(TYPE_PTR, encodeName(name2))], true);
25006
+ return this.forward(query, q);
25007
+ }
25008
+ if (q.type === TYPE_A || q.type === TYPE_AAAA) {
25009
+ const addresses = q.name === "" ? [] : await this.lookup(q.name);
25010
+ const answers2 = addresses.flatMap((a) => {
25011
+ const data = addressData(a, q.type);
25012
+ return data ? [record(q.type, data)] : [];
25013
+ });
25014
+ if (answers2.length > 0 || local(q.name) || await this.known(q.name)) {
25015
+ const rcode = addresses.length > 0 ? NOERROR : NXDOMAIN;
25016
+ return answerReply(query, q, rcode, answers2, local(q.name));
25017
+ }
25018
+ return this.forward(query, q);
25019
+ }
25020
+ if (await this.known(q.name)) return answerReply(query, q, NOERROR, [], true);
25021
+ if (local(q.name)) {
25022
+ const there = (await this.lookup(q.name)).length > 0;
25023
+ return answerReply(query, q, there ? NOERROR : NXDOMAIN, [], true);
24692
25024
  }
25025
+ return this.forward(query, q);
24693
25026
  }
24694
- return table;
25027
+ lookup(name2) {
25028
+ return this.resolver.resolve(name2, 0).catch(() => []);
25029
+ }
25030
+ known(name2) {
25031
+ return this.resolver.known(name2).catch(() => false);
25032
+ }
25033
+ reverse(address) {
25034
+ return this.resolver.reverse(address).catch(() => void 0);
25035
+ }
25036
+ async forward(query, q) {
25037
+ if (!this.forwarder) return answerReply(query, q, SERVFAIL, [], false);
25038
+ const asked = query.slice();
25039
+ asked[0] = 0;
25040
+ asked[1] = 0;
25041
+ const got = await this.forwarder(asked, AbortSignal.timeout(this.timeoutMs)).catch(
25042
+ () => void 0
25043
+ );
25044
+ if (!got || !answers(got, q)) return answerReply(query, q, SERVFAIL, [], false);
25045
+ const reply = got.slice();
25046
+ reply[0] = q.id >> 8;
25047
+ reply[1] = q.id & 255;
25048
+ return reply;
25049
+ }
25050
+ };
25051
+ async function collect(body, max) {
25052
+ const parts2 = [];
25053
+ let size = 0;
25054
+ for await (const part of body) {
25055
+ size += part.length;
25056
+ if (size > max) return void 0;
25057
+ parts2.push(part);
25058
+ }
25059
+ const out = new Uint8Array(size);
25060
+ let at = 0;
25061
+ for (const part of parts2) {
25062
+ out.set(part, at);
25063
+ at += part.length;
25064
+ }
25065
+ return out;
24695
25066
  }
24696
- function hostsReader(fs, path = HOSTS_PATH) {
24697
- let stamp = "";
24698
- let table;
24699
- return async () => {
24700
- const st = await fs.stat(path).catch(() => void 0);
24701
- if (!st?.isFile) {
24702
- stamp = "";
24703
- table = void 0;
25067
+ function dohForward(transport, url) {
25068
+ return async (query, signal) => {
25069
+ const res = await transport.fetch({
25070
+ url,
25071
+ method: "POST",
25072
+ headers: [
25073
+ ["content-type", MESSAGE],
25074
+ ["accept", MESSAGE]
25075
+ ],
25076
+ body: query,
25077
+ signal
25078
+ });
25079
+ const type = res.headers.find(([k]) => k.toLowerCase() === "content-type")?.[1] ?? "";
25080
+ if (res.status !== 200 || type.split(";")[0].trim().toLowerCase() !== MESSAGE) {
25081
+ await res.cancel().catch(() => void 0);
24704
25082
  return void 0;
24705
25083
  }
24706
- const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
24707
- if (now === stamp && table) return table;
24708
- const text = await fs.readFile(path).catch(() => void 0);
24709
- if (text === void 0) return void 0;
24710
- stamp = now;
24711
- table = parseHosts(text);
24712
- return table;
25084
+ return collect(res.body, DOH_MAX);
24713
25085
  };
24714
25086
  }
25087
+ function uplinkForward(uplink, server) {
25088
+ return async (query, signal) => {
25089
+ const conn = await uplink.dial({ network: "tcp", host: server, port: DNS_PORT, signal });
25090
+ const stop = () => conn.close();
25091
+ signal.addEventListener("abort", stop, { once: true });
25092
+ try {
25093
+ await conn.write(new Uint8Array([query.length >> 8, query.length & 255, ...query]));
25094
+ let got = new Uint8Array();
25095
+ for (; ; ) {
25096
+ if (got.length >= 2 && got.length >= 2 + u16(got, 0)) return got.slice(2, 2 + u16(got, 0));
25097
+ const piece = await conn.read();
25098
+ if (!piece) return void 0;
25099
+ const next3 = new Uint8Array(got.length + piece.length);
25100
+ next3.set(got);
25101
+ next3.set(piece, got.length);
25102
+ got = next3;
25103
+ }
25104
+ } finally {
25105
+ signal.removeEventListener("abort", stop);
25106
+ conn.close();
25107
+ }
25108
+ };
25109
+ }
25110
+ function dnsForward(uplink, transport, doh) {
25111
+ const server = uplink?.nameserver;
25112
+ if (uplink && server && (ipv4Bytes(server) || ipv6Groups(server)))
25113
+ return uplinkForward(uplink, server);
25114
+ return typeof doh === "string" ? dohForward(transport, doh) : void 0;
25115
+ }
25116
+ function kernelDnsStub(resolver, transport, uplink, doh) {
25117
+ return new DnsStub({ resolver, forward: dnsForward(uplink, transport, doh) });
25118
+ }
25119
+ async function readExactly(conn, size, signal) {
25120
+ const out = new Uint8Array(size);
25121
+ let at = 0;
25122
+ while (at < size) {
25123
+ const piece = await conn.read(size - at, signal);
25124
+ if (piece.length === 0) return void 0;
25125
+ out.set(piece, at);
25126
+ at += piece.length;
25127
+ }
25128
+ return out;
25129
+ }
25130
+ async function serveTcp(stub, conn) {
25131
+ try {
25132
+ for (; ; ) {
25133
+ const idle2 = AbortSignal.timeout(DNS_TCP_IDLE_MS);
25134
+ const size = await readExactly(conn, 2, idle2);
25135
+ if (!size) return;
25136
+ const query = await readExactly(conn, u16(size, 0), idle2);
25137
+ if (!query) return;
25138
+ const reply = await stub.answer(query, false);
25139
+ if (!reply) return;
25140
+ const framed = new Uint8Array([reply.length >> 8, reply.length & 255, ...reply]);
25141
+ const sent = await conn.write(framed, AbortSignal.timeout(DNS_TCP_IDLE_MS));
25142
+ if (sent < framed.length) return;
25143
+ }
25144
+ } catch {
25145
+ return;
25146
+ } finally {
25147
+ conn.close();
25148
+ }
25149
+ }
25150
+ function enableDnsStub(net, stub) {
25151
+ const at = { family: "inet", host: "127.0.0.1", port: DNS_PORT };
25152
+ net.reserve(DNS_PORT);
25153
+ net.kernelOnly(DNS_PORT, true);
25154
+ net.activate(at, () => {
25155
+ const listener = net.listen(at);
25156
+ const open2 = /* @__PURE__ */ new Set();
25157
+ void (async () => {
25158
+ for (; ; ) {
25159
+ const conn = await listener.accept().catch(() => void 0);
25160
+ if (!conn) return;
25161
+ if (open2.size >= DNS_TCP_MAX) {
25162
+ conn.close();
25163
+ continue;
25164
+ }
25165
+ open2.add(conn);
25166
+ void serveTcp(stub, conn).finally(() => open2.delete(conn));
25167
+ }
25168
+ })();
25169
+ });
25170
+ let inflight = 0;
25171
+ net.serveDgram(DNS_PORT, (datagram2, to) => {
25172
+ if (inflight >= DNS_UDP_INFLIGHT) return;
25173
+ inflight++;
25174
+ void stub.answer(datagram2.bytes, true).then(
25175
+ (reply) => {
25176
+ if (!reply) return;
25177
+ const from = { family: "inet", host: to.host, port: DNS_PORT };
25178
+ net.deliverDgram(datagram2.from.port, { bytes: reply, from });
25179
+ },
25180
+ () => void 0
25181
+ ).finally(() => inflight--);
25182
+ });
25183
+ }
24715
25184
 
24716
25185
  // src/kernel/net/redirect-hops.ts
24717
25186
  var HELD_MS = 3e4;
@@ -24719,13 +25188,13 @@ var HELD_MAX = 64;
24719
25188
  var HELD_PER_OWNER = 8;
24720
25189
  var MATCHED = ["range", "if-none-match", "if-modified-since", "if-range", "accept-encoding"];
24721
25190
  var KERNEL = -1;
24722
- function header2(headers, name2) {
25191
+ function header3(headers, name2) {
24723
25192
  const values = headers.filter(([n]) => n.toLowerCase() === name2).map(([, v]) => v);
24724
25193
  return values.length > 0 ? values.join(", ") : void 0;
24725
25194
  }
24726
25195
  function fingerprint(headers) {
24727
- const fields = MATCHED.map((name2) => header2(headers, name2) ?? "");
24728
- return JSON.stringify([...fields, header2(headers, "authorization") !== void 0]);
25196
+ const fields = MATCHED.map((name2) => header3(headers, name2) ?? "");
25197
+ return JSON.stringify([...fields, header3(headers, "authorization") !== void 0]);
24729
25198
  }
24730
25199
  function unauthorized(print) {
24731
25200
  return JSON.stringify([...JSON.parse(print).slice(0, -1), false]);
@@ -24768,7 +25237,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
24768
25237
  };
24769
25238
  const replay = (chain2) => {
24770
25239
  const [hop, ...rest2] = chain2.hops;
24771
- const location = hop && header2(hop.headers, "location");
25240
+ const location = hop && header3(hop.headers, "location");
24772
25241
  if (!hop || location === void 0) return chain2.final;
24773
25242
  const target = new URL(location, hop.url);
24774
25243
  target.hash = "";
@@ -24893,7 +25362,7 @@ function materializable(req) {
24893
25362
  if (req.shellGrants !== true && !isStrings(req.names)) return false;
24894
25363
  return isStrings(req.argv) && typeof req.path === "string" && typeof req.cwd === "string";
24895
25364
  }
24896
- function errorReply(code, message3) {
25365
+ function errorReply2(code, message3) {
24897
25366
  return { v: 1, error: { code, message: message3 } };
24898
25367
  }
24899
25368
  function isRecord(value2) {
@@ -24905,9 +25374,9 @@ function serialized(reply) {
24905
25374
  const text = JSON.stringify(reply);
24906
25375
  plain3 = text === void 0 ? void 0 : JSON.parse(text);
24907
25376
  } catch (err) {
24908
- return JSON.stringify(errorReply("EIO", lineOf2(err)));
25377
+ return JSON.stringify(errorReply2("EIO", lineOf2(err)));
24909
25378
  }
24910
- if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
25379
+ if (!isRecord(plain3)) return JSON.stringify(errorReply2("EIO", "the vault gave no reply"));
24911
25380
  const { v: _, ...rest2 } = plain3;
24912
25381
  return JSON.stringify({ v: 1, ...rest2 });
24913
25382
  }
@@ -24955,18 +25424,18 @@ var SealedChannel = class {
24955
25424
  }
24956
25425
  async answer(req, signal) {
24957
25426
  const hook = this.broker.hook;
24958
- if (!hook) return errorReply("ENOTCONN", "no vault is connected");
25427
+ if (!hook) return errorReply2("ENOTCONN", "no vault is connected");
24959
25428
  const stopped = new Promise((resolve2) => {
24960
25429
  signal.addEventListener("abort", () => resolve2(void 0), { once: true });
24961
25430
  });
24962
25431
  if (signal.aborted) return void 0;
24963
25432
  const asked = Promise.resolve().then(() => hook(req, { signal })).then(
24964
- (reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
24965
- (err) => errorReply("EIO", lineOf2(err))
25433
+ (reply2) => isRecord(reply2) ? reply2 : errorReply2("EIO", "the vault gave no reply"),
25434
+ (err) => errorReply2("EIO", lineOf2(err))
24966
25435
  );
24967
25436
  const reply = await Promise.race([asked, stopped]);
24968
25437
  if (!signal.aborted) return reply;
24969
- return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
25438
+ return signal.reason === "timeout" ? errorReply2("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
24970
25439
  }
24971
25440
  drop() {
24972
25441
  this.reply?.fill(0);
@@ -27312,6 +27781,10 @@ function blobModuleUrl(source) {
27312
27781
  const url = URL.createObjectURL(new Blob([source], { type: "text/javascript" }));
27313
27782
  return { url, revoke: () => URL.revokeObjectURL(url) };
27314
27783
  }
27784
+ function describe(req, tty) {
27785
+ const exe = req.exe === void 0 ? {} : { exe: req.exe };
27786
+ return { argv: [req.argv0, ...req.args], tty, started: Date.now(), ...exe };
27787
+ }
27315
27788
  function linksOf2(req) {
27316
27789
  return req.links === void 0 ? {} : { links: req.links };
27317
27790
  }
@@ -27333,6 +27806,7 @@ var LAYOUT = [
27333
27806
  ["/etc", 493],
27334
27807
  [PASSWD, 420],
27335
27808
  [GROUP, 420],
27809
+ [RESOLV_CONF_PATH, 420],
27336
27810
  ["/usr", 493],
27337
27811
  ["/usr/local", 493]
27338
27812
  ];
@@ -27675,6 +28149,10 @@ var Launcher = class {
27675
28149
  roots: packageTlsRoots(this.verifiedFs(options.fs), this.modulesDir),
27676
28150
  ca: this.ca
27677
28151
  });
28152
+ enableDnsStub(
28153
+ this.net,
28154
+ kernelDnsStub(this.resolver, this.transport, options.uplink, options.doh)
28155
+ );
27678
28156
  enableCdp(this.net, this.cdp);
27679
28157
  this.facades.enable(this.net);
27680
28158
  const fs = this.commandFs(this.base);
@@ -27762,10 +28240,10 @@ var Launcher = class {
27762
28240
  ready: () => this.fstab,
27763
28241
  lookup: (name2) => this.users.lookup(name2),
27764
28242
  watch: async (paths, notify) => {
27765
- const local = this.watchers.watch(paths, { recursive: true }, () => notify());
28243
+ const local2 = this.watchers.watch(paths, { recursive: true }, () => notify());
27766
28244
  const remote = await this.watchFiles(paths, notify);
27767
28245
  return () => {
27768
- local();
28246
+ local2();
27769
28247
  remote();
27770
28248
  };
27771
28249
  },
@@ -27951,7 +28429,7 @@ var Launcher = class {
27951
28429
  abi: "wasi",
27952
28430
  glue,
27953
28431
  wasm: glue,
27954
- argv0: baseName2(argv0 || file).replace(/\.wasm$/, ""),
28432
+ argv0,
27955
28433
  ...asked
27956
28434
  };
27957
28435
  }
@@ -28493,7 +28971,18 @@ var Launcher = class {
28493
28971
  const handle = await this.admitted(
28494
28972
  program.abi !== "js",
28495
28973
  req.fds,
28496
- (fds, quietOom) => this.start({ ...req, fds, quietOom, cwd, program, argv0: target.argv0, args, env, cwdSlot })
28974
+ (fds, quietOom) => this.start({
28975
+ ...req,
28976
+ fds,
28977
+ quietOom,
28978
+ cwd,
28979
+ program,
28980
+ argv0: target.argv0,
28981
+ exe: target.copy ?? target.glue,
28982
+ args,
28983
+ env,
28984
+ cwdSlot
28985
+ })
28497
28986
  ).finally(() => this.cwds.release(cwdSlot));
28498
28987
  void handle.exited.finally(done5);
28499
28988
  return handle;
@@ -28685,11 +29174,7 @@ var Launcher = class {
28685
29174
  if (req.pgid !== void 0) this.jobs.join(pid, req.pgid);
28686
29175
  if (req.group === "lead") this.jobs.lead(pid);
28687
29176
  if (req.group === "session") this.jobs.setsid(pid);
28688
- this.described.set(pid, {
28689
- argv: [req.argv0, ...req.args],
28690
- tty: terminal?.name ?? null,
28691
- started: Date.now()
28692
- });
29177
+ this.described.set(pid, describe(req, terminal?.name ?? null));
28693
29178
  handle.onState(
28694
29179
  (state) => state === "stopped" ? this.stopped.add(pid) : this.stopped.delete(pid)
28695
29180
  );
@@ -29297,6 +29782,19 @@ var Launcher = class {
29297
29782
  inUse(path) {
29298
29783
  return [...this.openFiles].some((nodes) => nodes.holds(path)) || heldUnder(this.held, path);
29299
29784
  }
29785
+ async resolvConf() {
29786
+ if (isProtected(this.prefixes, RESOLV_CONF_PATH)) return;
29787
+ try {
29788
+ const there = await this.base.lstat(RESOLV_CONF_PATH).then(
29789
+ () => true,
29790
+ () => false
29791
+ );
29792
+ if (there) return;
29793
+ await this.base.writeFile(RESOLV_CONF_PATH, RESOLV_CONF);
29794
+ } catch {
29795
+ return;
29796
+ }
29797
+ }
29300
29798
  async stampLayout() {
29301
29799
  const layout = [
29302
29800
  ...LAYOUT,
@@ -29432,6 +29930,7 @@ var Launcher = class {
29432
29930
  await this.mountShm();
29433
29931
  await this.pnpmReady();
29434
29932
  await this.users.ensure();
29933
+ await this.resolvConf();
29435
29934
  if (this.owners) await this.stampLayout();
29436
29935
  if (this.owners) await this.sudoer.provision();
29437
29936
  await writeCaFile(this.base, this.ca).catch(() => void 0);
@@ -29670,12 +30169,12 @@ var Launcher = class {
29670
30169
  const out = [];
29671
30170
  const err = [];
29672
30171
  const keep2 = options.collect !== false;
29673
- const collect = (chunks, tee) => (bytes) => {
30172
+ const collect2 = (chunks, tee) => (bytes) => {
29674
30173
  if (keep2) chunks.push(bytes);
29675
30174
  tee?.(bytes);
29676
30175
  };
29677
- const stdout = collect(out, options.onStdout);
29678
- const stderr = collect(err, options.onStderr);
30176
+ const stdout = collect2(out, options.onStdout);
30177
+ const stderr = collect2(err, options.onStderr);
29679
30178
  const report = (message3) => stderr(encoder10.encode(`${message3}
29680
30179
  `));
29681
30180
  if (!planned) {
@@ -30093,7 +30592,14 @@ function facadesOption(req, port) {
30093
30592
  function remotes(port, req) {
30094
30593
  return {
30095
30594
  ...req.transport ? { transport: new RemoteTransport(port, req.transport) } : {},
30096
- ...req.uplink ? { uplink: new RemoteUplink(port, req.uplink.traits, req.uplink.routes) } : {}
30595
+ ...req.uplink ? {
30596
+ uplink: new RemoteUplink(
30597
+ port,
30598
+ req.uplink.traits,
30599
+ req.uplink.routes,
30600
+ req.uplink.nameserver
30601
+ )
30602
+ } : {}
30097
30603
  };
30098
30604
  }
30099
30605
  function dial(l, req) {
@@ -30191,6 +30697,7 @@ function hostOptions(req, port, sealed, clipboard, lookup2) {
30191
30697
  return {
30192
30698
  cron: { lock: `slicc-kernel-cron:${req.metadata ?? META_DB}` },
30193
30699
  ...req.hostname !== void 0 ? { hostname: req.hostname } : {},
30700
+ ...req.doh !== void 0 ? { doh: req.doh } : {},
30194
30701
  ...req.users !== void 0 ? { users: req.users } : {},
30195
30702
  ...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
30196
30703
  ...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},