@ai-ecoverse/slicc-kernel 1.136.8 → 1.137.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.
@@ -2427,8 +2427,8 @@ var OpfsFs = class {
2427
2427
  renamingDirs = /* @__PURE__ */ new Set();
2428
2428
  intents = 0;
2429
2429
  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 }));
2430
+ const record2 = { ...rename, at: Date.now() * 1e3 + this.intents++ % 1e3 };
2431
+ await this.meta.update(at, () => ({ path: at, rename: record2 }));
2432
2432
  return at;
2433
2433
  }
2434
2434
  async rollBack(from, to, intents) {
@@ -2939,7 +2939,7 @@ async function rootId(factory, root, locks = globalThis.navigator?.locks) {
2939
2939
  const all = await request(
2940
2940
  db.transaction(ROOTS_STORE, "readonly").objectStore(ROOTS_STORE).getAll()
2941
2941
  );
2942
- for (const record of all) if (await same(record.handle, root)) return record.id;
2942
+ for (const record2 of all) if (await same(record2.handle, root)) return record2.id;
2943
2943
  const id2 = crypto.randomUUID();
2944
2944
  if (await used(root)) await seed(factory, nameOf(id2));
2945
2945
  const tx = db.transaction(ROOTS_STORE, "readwrite");
@@ -4879,6 +4879,15 @@ function isHostname(name2) {
4879
4879
  function ownNames(hostname) {
4880
4880
  return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
4881
4881
  }
4882
+ function hostsFile(hostname = DEFAULT_HOSTNAME) {
4883
+ return [
4884
+ "127.0.0.1 localhost localhost.localdomain",
4885
+ "::1 localhost ip6-localhost",
4886
+ `${HOSTNAME_ADDRESS} ${ownNames(hostname).join(" ")}`,
4887
+ `${HOST_LOOPBACK_ADDRESS.join(".")} ${HOST_LOOPBACK}`,
4888
+ ""
4889
+ ].join("\n");
4890
+ }
4882
4891
 
4883
4892
  // src/kernel/net/routes.ts
4884
4893
  var HOST_ADDRESS = HOST_LOOPBACK_ADDRESS.join(".");
@@ -5563,6 +5572,7 @@ var LOCAL_ONLY = new Routes();
5563
5572
  var LoopbackNet = class {
5564
5573
  bound = /* @__PURE__ */ new Map();
5565
5574
  dgrams = /* @__PURE__ */ new Map();
5575
+ dgramServices = /* @__PURE__ */ new Map();
5566
5576
  unixDgrams = /* @__PURE__ */ new Map();
5567
5577
  activators = /* @__PURE__ */ new Map();
5568
5578
  internal = /* @__PURE__ */ new Set();
@@ -5613,9 +5623,16 @@ var LoopbackNet = class {
5613
5623
  releaseDgram(addr, socket) {
5614
5624
  if (this.dgrams.get(addr.port) === socket) this.dgrams.delete(addr.port);
5615
5625
  }
5616
- deliverDgram(port, datagram2) {
5626
+ serveDgram(port, serve) {
5627
+ this.dgramServices.set(port, serve);
5628
+ }
5629
+ deliverDgram(port, datagram2, to) {
5617
5630
  const target = this.dgrams.get(port);
5618
- return target ? target.deliver(datagram2) : false;
5631
+ if (target) return target.deliver(datagram2);
5632
+ const service = this.dgramServices.get(port);
5633
+ if (!service) return false;
5634
+ service(datagram2, to ?? { family: "inet", host: "127.0.0.1", port });
5635
+ return true;
5619
5636
  }
5620
5637
  bindable(addr, kernel) {
5621
5638
  if (addr.host !== "0.0.0.0" && !isLoopback(addr.host)) {
@@ -7098,7 +7115,7 @@ function satisfies(version, range2) {
7098
7115
  }
7099
7116
 
7100
7117
  // src/version.ts
7101
- var KERNEL_VERSION = true ? "1.136.8" : "0.0.0-dev";
7118
+ var KERNEL_VERSION = true ? "1.137.0" : "0.0.0-dev";
7102
7119
  var OS_RELEASE = "6.0.0-slicc";
7103
7120
  function procVersion() {
7104
7121
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -8616,11 +8633,11 @@ var CronService = class {
8616
8633
  }
8617
8634
  if (this.stopping.signal.aborted) return;
8618
8635
  const exit = ended.signal ? `signal=${ended.signal}` : `exit=${ended.status}`;
8619
- const header3 = encoder.encode(`--- ${iso} ${exit} missed=${missed} ---
8636
+ const header4 = encoder.encode(`--- ${iso} ${exit} missed=${missed} ---
8620
8637
  `);
8621
8638
  const body = output.bytes();
8622
8639
  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(
8640
+ await this.append(log, concat2([header4, body, newline]), account.uid, account.gid).catch(
8624
8641
  (err) => this.error(messageOf(err))
8625
8642
  );
8626
8643
  }
@@ -9428,8 +9445,8 @@ var FileWatches = class {
9428
9445
  live = /* @__PURE__ */ new Set();
9429
9446
  local;
9430
9447
  remote;
9431
- constructor(local, remote) {
9432
- this.local = local;
9448
+ constructor(local2, remote) {
9449
+ this.local = local2;
9433
9450
  this.remote = remote;
9434
9451
  }
9435
9452
  announce() {
@@ -13149,18 +13166,18 @@ var SAB_I_ASYNC = 14;
13149
13166
  var SAB_I_STOP = 15;
13150
13167
  var SAB_I_BLOCKED = 16;
13151
13168
  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)];
13169
+ function loadBlocked(header4) {
13170
+ return [Atomics.load(header4, SAB_I_BLOCKED), Atomics.load(header4, SAB_I_BLOCKED_HI)];
13154
13171
  }
13155
- function storeBlocked(header3, [low, high]) {
13156
- Atomics.store(header3, SAB_I_BLOCKED_HI, high);
13157
- Atomics.store(header3, SAB_I_BLOCKED, low);
13172
+ function storeBlocked(header4, [low, high]) {
13173
+ Atomics.store(header4, SAB_I_BLOCKED_HI, high);
13174
+ Atomics.store(header4, SAB_I_BLOCKED, low);
13158
13175
  }
13159
13176
  var anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
13160
13177
  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);
13178
+ function storeU53(header4, lo, hi, value2) {
13179
+ Atomics.store(header4, hi, Math.floor(value2 / U32));
13180
+ Atomics.store(header4, lo, value2 % U32 | 0);
13164
13181
  }
13165
13182
  var SAB_STATE_READY = 2;
13166
13183
  var SAB_STATUS_BYTES = 1;
@@ -13209,7 +13226,7 @@ function sabViews(sab) {
13209
13226
  var PENDING_TTL_MS = SYNC_FS_REQUEST_TIMEOUT_MS + 5e3;
13210
13227
  function attachSyncSabResponder(port, sab, token, opts) {
13211
13228
  const views = sabViews(sab);
13212
- const { header: header3, window } = views;
13229
+ const { header: header4, window } = views;
13213
13230
  const pending = /* @__PURE__ */ new Map();
13214
13231
  let disposed = false;
13215
13232
  const { dispatch: dispatch2 } = opts;
@@ -13220,20 +13237,20 @@ function attachSyncSabResponder(port, sab, token, opts) {
13220
13237
  pending.delete(id2);
13221
13238
  }
13222
13239
  function publish(id2, entry, offset) {
13223
- if (Atomics.load(header3, SAB_I_REQ) !== id2) {
13240
+ if (Atomics.load(header4, SAB_I_REQ) !== id2) {
13224
13241
  drop(id2);
13225
13242
  return;
13226
13243
  }
13227
13244
  const chunk2 = Math.min(window.byteLength, entry.payload.byteLength - offset);
13228
13245
  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);
13246
+ Atomics.store(header4, SAB_I_STATUS, entry.status);
13247
+ storeU53(header4, SAB_I_TOTAL, SAB_I_TOTAL_HI, entry.payload.byteLength);
13248
+ Atomics.store(header4, SAB_I_CHUNK, chunk2);
13249
+ storeU53(header4, SAB_I_OFFSET, SAB_I_OFFSET_HI, offset);
13250
+ Atomics.store(header4, SAB_I_SEQ, id2);
13251
+ Atomics.store(header4, SAB_I_STATE, SAB_STATE_READY);
13252
+ Atomics.add(header4, SAB_I_PUB, 1);
13253
+ Atomics.notify(header4, SAB_I_PUB);
13237
13254
  if (offset + chunk2 >= entry.payload.byteLength) drop(id2);
13238
13255
  else if (entry.timer) {
13239
13256
  clearTimeout(entry.timer);
@@ -13448,6 +13465,15 @@ var ProcessClocks = class {
13448
13465
  }
13449
13466
  };
13450
13467
 
13468
+ // src/kernel/proc-info.ts
13469
+ function mayTrace(viewer, target) {
13470
+ const by = viewer?.cred;
13471
+ const of = target.cred;
13472
+ if (!by || !of || by.euid === 0) return true;
13473
+ const uid = of.ruid === by.euid && of.euid === by.euid && of.suid === by.euid;
13474
+ return uid && of.rgid === by.egid && of.egid === by.egid && of.sgid === by.egid;
13475
+ }
13476
+
13451
13477
  // src/fs/pages.ts
13452
13478
  var PAGE = 64 * 1024;
13453
13479
  var READAHEAD = 1024 * 1024;
@@ -14003,7 +14029,16 @@ var ProcTree = class {
14003
14029
  if (!/^[1-9]\d*$/.test(top) || !this.alive(Number(top))) return void 0;
14004
14030
  if (leaf === "task") return this.task(Number(top), rest2);
14005
14031
  if (rest2.length > 0) return void 0;
14006
- if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES, "task"] };
14032
+ if (leaf === void 0) {
14033
+ const exe = () => this.info(Number(top))?.exe === void 0 ? [] : ["exe"];
14034
+ return { kind: "dir", names: () => [...PID_NAMES, ...exe(), "task"] };
14035
+ }
14036
+ if (leaf === "exe") {
14037
+ const info = this.info(Number(top));
14038
+ if (info?.exe === void 0) return void 0;
14039
+ const denied2 = !mayTrace(this.ownInfo(), info);
14040
+ return { kind: "link", target: info.exe, ...denied2 ? { denied: denied2 } : {} };
14041
+ }
14007
14042
  if (!PID_NAMES.includes(leaf)) return void 0;
14008
14043
  return {
14009
14044
  kind: "file",
@@ -14015,6 +14050,10 @@ var ProcTree = class {
14015
14050
  }
14016
14051
  };
14017
14052
  }
14053
+ ownInfo() {
14054
+ const processes2 = this.listing().processes;
14055
+ return processes2.find((p) => p.tid === this.pid) ?? processes2.find((p) => p.pid === this.pid);
14056
+ }
14018
14057
  info(pid) {
14019
14058
  return this.listing().processes.find((p) => p.pid === pid);
14020
14059
  }
@@ -14078,6 +14117,7 @@ var ProcTree = class {
14078
14117
  readlink(path) {
14079
14118
  const node = this.find(path, false);
14080
14119
  if (node.kind !== "link") throw syncError("EINVAL", path);
14120
+ if (node.denied) throw syncError("EACCES", path);
14081
14121
  return node.target;
14082
14122
  }
14083
14123
  exists(path) {
@@ -15482,8 +15522,8 @@ function sameCert(a, b) {
15482
15522
  if (!a || !b) return a === b;
15483
15523
  return a.cert.length === b.cert.length && a.cert.every((byte, i) => byte === b.cert[i]);
15484
15524
  }
15485
- function winner(current, expected, record) {
15486
- return sameCert(current, expected) ? record : current;
15525
+ function winner(current, expected, record2) {
15526
+ return sameCert(current, expected) ? record2 : current;
15487
15527
  }
15488
15528
  var DAY = 24 * 60 * 60 * 1e3;
15489
15529
  var CA_LIFETIME = 3650 * DAY;
@@ -15516,15 +15556,15 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
15516
15556
  const store = (await open2()).transaction("ca").objectStore("ca");
15517
15557
  return await request2(store.get(owner));
15518
15558
  },
15519
- async swap(owner, expected, record) {
15559
+ async swap(owner, expected, record2) {
15520
15560
  const tx = (await open2()).transaction("ca", "readwrite");
15521
15561
  const store = tx.objectStore("ca");
15522
- let stored = record;
15562
+ let stored = record2;
15523
15563
  const read = store.get(owner);
15524
15564
  read.onsuccess = () => {
15525
15565
  const current = read.result;
15526
- const kept = winner(current, expected, record);
15527
- if (kept === record) store.put(record, owner);
15566
+ const kept = winner(current, expected, record2);
15567
+ if (kept === record2) store.put(record2, owner);
15528
15568
  else stored = kept;
15529
15569
  };
15530
15570
  await new Promise((resolve2, reject) => {
@@ -15544,14 +15584,14 @@ function validLeafName(host) {
15544
15584
  }
15545
15585
  var RealmCa = class _RealmCa {
15546
15586
  record;
15547
- constructor(record) {
15548
- this.record = record;
15587
+ constructor(record2) {
15588
+ this.record = record2;
15549
15589
  }
15550
15590
  static async open(owner, store, now = Date.now()) {
15551
15591
  const stored = await store.get(owner).catch(() => void 0);
15552
15592
  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));
15593
+ const record2 = await _RealmCa.create(owner, now);
15594
+ return new _RealmCa(await store.swap(owner, stored, record2));
15555
15595
  }
15556
15596
  static async create(owner, now) {
15557
15597
  const pair = await crypto.subtle.generateKey(ECDSA, false, ["sign", "verify"]);
@@ -16082,8 +16122,8 @@ function memoryCaStore() {
16082
16122
  const records = /* @__PURE__ */ new Map();
16083
16123
  return {
16084
16124
  get: async (owner) => records.get(owner),
16085
- swap: async (owner, expected, record) => {
16086
- const kept = winner(records.get(owner), expected, record);
16125
+ swap: async (owner, expected, record2) => {
16126
+ const kept = winner(records.get(owner), expected, record2);
16087
16127
  records.set(owner, kept);
16088
16128
  return kept;
16089
16129
  }
@@ -16213,10 +16253,10 @@ var WsHandles = class {
16213
16253
  open = /* @__PURE__ */ new Map();
16214
16254
  next;
16215
16255
  local;
16216
- constructor(transport, next3, local) {
16256
+ constructor(transport, next3, local2) {
16217
16257
  this.transport = transport;
16218
16258
  this.next = next3;
16219
- this.local = local;
16259
+ this.local = local2;
16220
16260
  }
16221
16261
  owns(handle) {
16222
16262
  return this.open.has(handle);
@@ -16245,8 +16285,8 @@ var WsHandles = class {
16245
16285
  return { ok: true, kind: "json", json: handle };
16246
16286
  }
16247
16287
  async connect(handle, req, entry) {
16248
- const { transport, local } = this;
16249
- const port = local?.port(req.url);
16288
+ const { transport, local: local2 } = this;
16289
+ const port = local2?.port(req.url);
16250
16290
  const open2 = { protocols: req.protocols, headers: req.headers, signal: entry.abort.signal };
16251
16291
  if (port === void 0 && (!transport.traits.websocket || !transport.websocket)) {
16252
16292
  return fail("ENOTSUP", NO_WEBSOCKET2);
@@ -16256,7 +16296,7 @@ var WsHandles = class {
16256
16296
  socket = port === void 0 ? await transport.websocket({
16257
16297
  url: toHostLoopback(req.url),
16258
16298
  ...open2
16259
- }) : await local.websocket({ url: req.url, ...open2 }, port);
16299
+ }) : await local2.websocket({ url: req.url, ...open2 }, port);
16260
16300
  } catch (e) {
16261
16301
  return fail(errnoOf(e), message(e));
16262
16302
  }
@@ -16387,11 +16427,11 @@ var HttpHandles = class {
16387
16427
  ws;
16388
16428
  owner;
16389
16429
  local;
16390
- constructor(transport, owner, local) {
16430
+ constructor(transport, owner, local2) {
16391
16431
  this.transport = transport;
16392
16432
  this.owner = owner;
16393
- this.local = local;
16394
- this.ws = new WsHandles(transport, () => ++this.nextHandle, local);
16433
+ this.local = local2;
16434
+ this.ws = new WsHandles(transport, () => ++this.nextHandle, local2);
16395
16435
  }
16396
16436
  syscall(req) {
16397
16437
  if (req.op.startsWith("net-ws-")) return this.ws.syscall(req);
@@ -16543,6 +16583,43 @@ var HttpHandles = class {
16543
16583
  }
16544
16584
  };
16545
16585
 
16586
+ // src/kernel/net/hosts-file.ts
16587
+ var HOSTS_PATH = "/etc/hosts";
16588
+ function parseHosts(text) {
16589
+ const table = /* @__PURE__ */ new Map();
16590
+ for (const raw2 of text.split("\n")) {
16591
+ const [address, ...names2] = raw2.replace(/#.*/, "").trim().split(/\s+/);
16592
+ if (!address || names2.length === 0) continue;
16593
+ if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
16594
+ for (const name2 of names2) {
16595
+ const key = name2.toLowerCase().replace(/\.$/, "");
16596
+ const known = table.get(key) ?? [];
16597
+ if (!known.includes(address)) known.push(address);
16598
+ table.set(key, known);
16599
+ }
16600
+ }
16601
+ return table;
16602
+ }
16603
+ function hostsReader(fs, path = HOSTS_PATH) {
16604
+ let stamp = "";
16605
+ let table;
16606
+ return async () => {
16607
+ const st = await fs.stat(path).catch(() => void 0);
16608
+ if (!st?.isFile) {
16609
+ stamp = "";
16610
+ table = void 0;
16611
+ return void 0;
16612
+ }
16613
+ const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
16614
+ if (now === stamp && table) return table;
16615
+ const text = await fs.readFile(path).catch(() => void 0);
16616
+ if (text === void 0) return void 0;
16617
+ stamp = now;
16618
+ table = parseHosts(text);
16619
+ return table;
16620
+ };
16621
+ }
16622
+
16546
16623
  // src/kernel/net/uplink.ts
16547
16624
  function carriesUdp(uplink) {
16548
16625
  return uplink.traits.udp === true && typeof uplink.udp === "function";
@@ -16559,13 +16636,15 @@ var NEVER = new Routes(true);
16559
16636
  var RemoteUplink = class {
16560
16637
  traits;
16561
16638
  routes;
16639
+ nameserver;
16562
16640
  port;
16563
16641
  waiting = /* @__PURE__ */ new Map();
16564
16642
  nextId = 0;
16565
- constructor(port, traits, routes) {
16643
+ constructor(port, traits, routes, nameserver) {
16566
16644
  this.port = port;
16567
16645
  this.traits = traits;
16568
16646
  this.routes = routes;
16647
+ this.nameserver = nameserver;
16569
16648
  }
16570
16649
  receive(reply) {
16571
16650
  const waiter = this.waiting.get(reply.uid);
@@ -16688,6 +16767,7 @@ var Resolver = class {
16688
16767
  timeoutMs;
16689
16768
  log;
16690
16769
  own;
16770
+ builtin;
16691
16771
  cache = /* @__PURE__ */ new Map();
16692
16772
  pending = /* @__PURE__ */ new Map();
16693
16773
  hosts;
@@ -16698,6 +16778,7 @@ var Resolver = class {
16698
16778
  this.timeoutMs = options.timeoutMs ?? RESOLVE_TIMEOUT_MS;
16699
16779
  this.log = options.log ?? ((message3) => console.warn(message3));
16700
16780
  this.own = ownNames(options.hostname ?? DEFAULT_HOSTNAME);
16781
+ this.builtin = parseHosts(hostsFile(options.hostname ?? DEFAULT_HOSTNAME));
16701
16782
  this.hosts = options.hosts;
16702
16783
  }
16703
16784
  async fromFile(key, family) {
@@ -16707,18 +16788,34 @@ var Resolver = class {
16707
16788
  const v6 = listed.filter((a) => ipv4Bytes(a) === void 0);
16708
16789
  return family === 4 ? v4 : family === 6 ? v6 : [...v4, ...v6];
16709
16790
  }
16791
+ async known(name2) {
16792
+ const key = name2.toLowerCase().replace(/\.$/, "");
16793
+ if (ipv4Bytes(key) || ipv6Groups(key)) return false;
16794
+ if (hostsEntry(key, this.own) !== void 0) return true;
16795
+ return ((await this.hosts?.().catch(() => void 0))?.get(key)?.length ?? 0) > 0;
16796
+ }
16797
+ async reverse(address) {
16798
+ const v6 = ipv6Groups(address)?.join(":");
16799
+ const same3 = (a) => a === address || v6 !== void 0 && ipv6Groups(a)?.join(":") === v6;
16800
+ const file = await this.hosts?.().catch(() => void 0);
16801
+ for (const table of [file, this.builtin]) {
16802
+ for (const [name2, addresses] of table ?? []) if (addresses.some(same3)) return name2;
16803
+ }
16804
+ if (ipv4Bytes(address)?.[0] === 127) return "localhost";
16805
+ return void 0;
16806
+ }
16710
16807
  async resolve(name2, family, blocking) {
16711
16808
  const key = name2.toLowerCase().replace(/\.$/, "");
16712
- const local = hostsEntry(key, this.own);
16809
+ const local2 = hostsEntry(key, this.own);
16713
16810
  if (ipv6Groups(key)) {
16714
- const v4 = family !== 6 && local ? [local] : [];
16811
+ const v4 = family !== 6 && local2 ? [local2] : [];
16715
16812
  return family === 4 ? v4 : [...v4, key];
16716
16813
  }
16717
16814
  const listed = this.hosts ? await this.fromFile(key, family) : void 0;
16718
16815
  if (listed?.length) return listed;
16719
- if (local) {
16816
+ if (local2) {
16720
16817
  const six = loopbackName(key, this.own) ? ["::1"] : [];
16721
- return family === 6 ? six : family === 4 ? [local] : [local, ...six];
16818
+ return family === 6 ? six : family === 4 ? [local2] : [local2, ...six];
16722
16819
  }
16723
16820
  if (!this.uplink || key === "") return [];
16724
16821
  const asked = this.uplink.traits.ipv6 ? family : 4;
@@ -17757,14 +17854,15 @@ var KernelDgram = class {
17757
17854
  const max = familyOf(target.host) === 6 ? MAX_DATAGRAM_V6 : MAX_DATAGRAM_V4;
17758
17855
  if (bytes.length > max) throw new KernelError("EMSGSIZE");
17759
17856
  const where = this.route(target.host);
17760
- const local = this.bound();
17857
+ const local2 = this.bound();
17761
17858
  if (where === "uplink") return this.sendUp(bytes, target);
17762
17859
  const from = {
17763
17860
  family: "inet",
17764
- host: local.host === "0.0.0.0" ? "127.0.0.1" : local.host,
17765
- port: local.port
17861
+ host: local2.host === "0.0.0.0" ? "127.0.0.1" : local2.host,
17862
+ port: local2.port
17766
17863
  };
17767
- const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from });
17864
+ const dest = { family: "inet", host: canonicalHost(target.host), port: target.port };
17865
+ const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from }, dest);
17768
17866
  if (!delivered && this.peer && sameAddr(this.peer, target)) {
17769
17867
  this.pending = "ECONNREFUSED";
17770
17868
  this.changes.wake();
@@ -19361,8 +19459,8 @@ function clientFirstOf(message3) {
19361
19459
  return m ? { header: m[1], bare: m[2] } : void 0;
19362
19460
  }
19363
19461
  var latinBytes = (text) => Uint8Array.from(text, (c) => c.charCodeAt(0));
19364
- function channelOf(header3, binding) {
19365
- const head = latinBytes(header3);
19462
+ function channelOf(header4, binding) {
19463
+ const head = latinBytes(header4);
19366
19464
  const all = new Uint8Array(head.length + (binding?.length ?? 0));
19367
19465
  all.set(head);
19368
19466
  if (binding) all.set(binding, head.length);
@@ -19484,6 +19582,7 @@ function latin2(bytes) {
19484
19582
  var PgServer = class {
19485
19583
  binding;
19486
19584
  plus = false;
19585
+ touch;
19487
19586
  constructor(binding) {
19488
19587
  this.binding = binding;
19489
19588
  }
@@ -19505,6 +19604,7 @@ var PgServer = class {
19505
19604
  return message3;
19506
19605
  }
19507
19606
  mechanisms(message3) {
19607
+ if (this.touch !== true) return message3;
19508
19608
  this.sasl = true;
19509
19609
  const offered = latin2(message3.subarray(9)).split("\0").filter((n) => n !== "");
19510
19610
  this.plus = offered.includes(PLUS);
@@ -19585,8 +19685,8 @@ function frame3(type, body) {
19585
19685
  return out;
19586
19686
  }
19587
19687
  function pgLength(bytes, started) {
19588
- const header3 = started ? 5 : 4;
19589
- if (bytes.length < header3) return void 0;
19688
+ const header4 = started ? 5 : 4;
19689
+ if (bytes.length < header4) return void 0;
19590
19690
  const length2 = int32(bytes, started ? 1 : 0);
19591
19691
  return started ? 1 + length2 : length2;
19592
19692
  }
@@ -19614,16 +19714,16 @@ function initial(message3) {
19614
19714
  function int32Text(n) {
19615
19715
  return String.fromCharCode(n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255);
19616
19716
  }
19617
- function serverHeader(header3, server) {
19618
- if (header3 === "n,,") return header3;
19619
- if (header3 === "y,," && !server.plus) return header3;
19620
- if (header3 === END_POINT && server.binding) return header3;
19717
+ function serverHeader(header4, server) {
19718
+ if (header4 === "n,,") return header4;
19719
+ if (header4 === "y,," && !server.plus) return header4;
19720
+ if (header4 === END_POINT && server.binding) return header4;
19621
19721
  return server.plus && server.binding ? END_POINT : "n,,";
19622
19722
  }
19623
- function rewritten(first, header3) {
19723
+ function rewritten(first, header4) {
19624
19724
  const parsed2 = clientFirstOf(first.data);
19625
- if (!parsed2 || parsed2.header === header3) return first;
19626
- return { mechanism: header3 === END_POINT ? PLUS : PLAIN, data: `${header3}${parsed2.bare}` };
19725
+ if (!parsed2 || parsed2.header === header4) return first;
19726
+ return { mechanism: header4 === END_POINT ? PLUS : PLAIN, data: `${header4}${parsed2.bare}` };
19627
19727
  }
19628
19728
  var PgClient = class {
19629
19729
  clientFirst;
@@ -19864,6 +19964,10 @@ var SessionWriter = class {
19864
19964
  this.proven ??= this.prove(protocol).catch(() => void 0);
19865
19965
  return this.proven;
19866
19966
  }
19967
+ async mayTouch() {
19968
+ if (this.s.verified) return true;
19969
+ return (await this.proof("pg"))?.anchor !== void 0;
19970
+ }
19867
19971
  async prove(protocol) {
19868
19972
  const s = this.s;
19869
19973
  if (s.anchoring) {
@@ -19913,7 +20017,10 @@ var SessionWriter = class {
19913
20017
  this.buffer.fill(0);
19914
20018
  this.buffer = joined4;
19915
20019
  if (this.mode === "sniff") this.mode = modeOf(latin12(joined4.subarray(0, 8))) ?? "sniff";
19916
- if (this.mode === "pg") this.sawPg = true;
20020
+ if (this.mode === "pg" && !this.sawPg) {
20021
+ this.sawPg = true;
20022
+ if (!this.s.verified) void this.proof("pg");
20023
+ }
19917
20024
  if (this.mode === "pass") await this.release();
19918
20025
  else if (this.mode === "http1") await this.http1();
19919
20026
  else if (this.mode === "smtp") await this.lines();
@@ -20093,6 +20200,7 @@ function sealedConn(conn, s) {
20093
20200
  for (; ; ) {
20094
20201
  const bytes = await conn.read();
20095
20202
  if (!bytes) return bytes;
20203
+ if (writer?.sawPg && pg.touch === void 0) pg.touch = await writer.mayTouch();
20096
20204
  const out = writer?.sawPg ? pg.filter(bytes) : bytes;
20097
20205
  if (pg.failed) {
20098
20206
  conn.close();
@@ -20740,8 +20848,8 @@ async function datagram(req, proc) {
20740
20848
  const ready2 = pollFile(dgram).readable;
20741
20849
  if (req.nonblock && !ready2) throw new KernelError("EAGAIN");
20742
20850
  const got = await dgram.receive(req.max, req.peek, ready2 ? void 0 : proc.blocking());
20743
- const { bytes, from, truncated } = got;
20744
- return { ok: true, kind: "bytes", bytes: encodeReceived({ bytes, truncated, ...from }) };
20851
+ const { bytes, from, truncated: truncated2 } = got;
20852
+ return { ok: true, kind: "bytes", bytes: encodeReceived({ bytes, truncated: truncated2, ...from }) };
20745
20853
  }
20746
20854
  async function unixDatagram(req, dgram, proc) {
20747
20855
  if (req.op === "sock-sendto") {
@@ -20751,11 +20859,11 @@ async function unixDatagram(req, dgram, proc) {
20751
20859
  const ready2 = pollFile(dgram).readable;
20752
20860
  if (req.nonblock && !ready2) throw new KernelError("EAGAIN");
20753
20861
  const got = await dgram.receive(req.max, req.peek, ready2 ? void 0 : proc.blocking());
20754
- const { bytes, from, truncated } = got;
20862
+ const { bytes, from, truncated: truncated2 } = got;
20755
20863
  return {
20756
20864
  ok: true,
20757
20865
  kind: "bytes",
20758
- bytes: encodeReceived({ bytes, truncated, host: from.path, port: 0, unix: true })
20866
+ bytes: encodeReceived({ bytes, truncated: truncated2, host: from.path, port: 0, unix: true })
20759
20867
  };
20760
20868
  }
20761
20869
  function domainOf(socket) {
@@ -23506,9 +23614,9 @@ var JsThreads = class {
23506
23614
  const { control, port } = msg;
23507
23615
  const tid = ++this.last;
23508
23616
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
23509
- const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
23617
+ const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
23510
23618
  const owned4 = new SharedArrayBuffer(4 * (1 + JS_THREAD_OWNED_FDS));
23511
- if (this.frozen) Atomics.store(header3, SAB_I_STOP, 1);
23619
+ if (this.frozen) Atomics.store(header4, SAB_I_STOP, 1);
23512
23620
  const clock = this.deps.clocks.thread(tid + 1, sab);
23513
23621
  let ended = false;
23514
23622
  const end = (code) => {
@@ -23516,7 +23624,7 @@ var JsThreads = class {
23516
23624
  ended = true;
23517
23625
  this.live.delete(tid);
23518
23626
  this.headers.delete(tid);
23519
- this.deps.wakes.delete(header3);
23627
+ this.deps.wakes.delete(header4);
23520
23628
  for (const [id2, token] of ops) {
23521
23629
  void this.deps.dispatch({ op: "async-cancel", id: id2, token });
23522
23630
  }
@@ -23566,8 +23674,8 @@ var JsThreads = class {
23566
23674
  control.addEventListener("message", onControl);
23567
23675
  control.start();
23568
23676
  this.live.set(tid, end);
23569
- this.headers.set(tid, header3);
23570
- this.deps.wakes.add(header3);
23677
+ this.headers.set(tid, header4);
23678
+ this.deps.wakes.add(header4);
23571
23679
  const init = {
23572
23680
  ...this.deps.init(sab, lane.lane),
23573
23681
  type: JS_THREAD_INIT,
@@ -23587,9 +23695,9 @@ var JsThreads = class {
23587
23695
  }
23588
23696
  stopped(stopped) {
23589
23697
  this.frozen = stopped;
23590
- for (const header3 of this.headers.values()) {
23591
- Atomics.store(header3, SAB_I_STOP, stopped ? 1 : 0);
23592
- Atomics.notify(header3, SAB_I_STOP);
23698
+ for (const header4 of this.headers.values()) {
23699
+ Atomics.store(header4, SAB_I_STOP, stopped ? 1 : 0);
23700
+ Atomics.notify(header4, SAB_I_STOP);
23593
23701
  }
23594
23702
  }
23595
23703
  close() {
@@ -23634,13 +23742,13 @@ var Dying = class {
23634
23742
  hard;
23635
23743
  busy = 0;
23636
23744
  finish;
23637
- start(code, sig, header3, process, finish) {
23745
+ start(code, sig, header4, process, finish) {
23638
23746
  if (this.ending) return;
23639
23747
  this.ending = { code, sig };
23640
23748
  this.finish = finish;
23641
23749
  this.hard = setTimeout(finish, KILL_HARD_MS);
23642
23750
  this.arm();
23643
- Atomics.store(header3, SAB_I_KILLED, code);
23751
+ Atomics.store(header4, SAB_I_KILLED, code);
23644
23752
  process.die();
23645
23753
  }
23646
23754
  serve(req, work) {
@@ -23687,8 +23795,8 @@ function unblockedThread(threads, sig) {
23687
23795
  }
23688
23796
  return void 0;
23689
23797
  }
23690
- function unblocked(header3) {
23691
- return Atomics.load(header3, SAB_I_SIGNALS) & ~Atomics.load(header3, SAB_I_BLOCKED);
23798
+ function unblocked(header4) {
23799
+ return Atomics.load(header4, SAB_I_SIGNALS) & ~Atomics.load(header4, SAB_I_BLOCKED);
23692
23800
  }
23693
23801
  function threadCall(process, req, cancelled, block) {
23694
23802
  return isWasmSyscall(req) ? process.syscall(req, cancelled, block) : dispatchSyncFs(req);
@@ -23700,24 +23808,24 @@ function threadCancel(thread) {
23700
23808
  return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
23701
23809
  }
23702
23810
  var asyncFanout = /* @__PURE__ */ new WeakMap();
23703
- function notifiers(header3) {
23811
+ function notifiers(header4) {
23704
23812
  return {
23705
23813
  onPending(sig) {
23706
- Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig));
23707
- Atomics.notify(header3, SAB_I_SIGNALS);
23814
+ Atomics.or(header4, SAB_I_SIGNALS, sigbit(sig));
23815
+ Atomics.notify(header4, SAB_I_SIGNALS);
23708
23816
  },
23709
23817
  onAsync() {
23710
- for (const at of [header3, ...asyncFanout.get(header3) ?? []]) {
23818
+ for (const at of [header4, ...asyncFanout.get(header4) ?? []]) {
23711
23819
  Atomics.add(at, SAB_I_ASYNC, 1);
23712
23820
  Atomics.notify(at, SAB_I_ASYNC);
23713
23821
  }
23714
23822
  }
23715
23823
  };
23716
23824
  }
23717
- function publishStops(process, header3) {
23825
+ function publishStops(process, header4) {
23718
23826
  process.onState((state) => {
23719
- Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
23720
- Atomics.notify(header3, SAB_I_STOP);
23827
+ Atomics.store(header4, SAB_I_STOP, state === "stopped" ? 1 : 0);
23828
+ Atomics.notify(header4, SAB_I_STOP);
23721
23829
  });
23722
23830
  }
23723
23831
  function transferOf(opts, lane) {
@@ -23809,7 +23917,7 @@ function linksOf(opts) {
23809
23917
  function clipboardName(opts) {
23810
23918
  return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
23811
23919
  }
23812
- function processOptions(opts, header3, hooks, created4) {
23920
+ function processOptions(opts, header4, hooks, created4) {
23813
23921
  return {
23814
23922
  ...inherited(opts),
23815
23923
  ...opts.owners ? { owners: true } : {},
@@ -23848,16 +23956,16 @@ function processOptions(opts, header3, hooks, created4) {
23848
23956
  watches: opts.watches,
23849
23957
  onReap: opts.onReap,
23850
23958
  resolver: opts.resolver,
23851
- ...notifiers(header3),
23852
- onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
23853
- hasPending: () => unblocked(header3) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
23959
+ ...notifiers(header4),
23960
+ onTimer: (which) => void Atomics.or(header4, SAB_I_TIMERS, 1 << which),
23961
+ hasPending: () => unblocked(header4) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
23854
23962
  raise: hooks.raise,
23855
23963
  threadKill: hooks.threadKill,
23856
23964
  unblockedThread: hooks.unblockedThread,
23857
23965
  ...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
23858
23966
  ...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
23859
- ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {},
23860
- ...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header3, SAB_I_BLOCKED) } : {}
23967
+ ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {},
23968
+ ...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header4, SAB_I_BLOCKED) } : {}
23861
23969
  };
23862
23970
  }
23863
23971
  function threadInit(opts, program, sab, cred, thread, main) {
@@ -23923,9 +24031,9 @@ async function crashReport(process, onError, message3) {
23923
24031
  function spawnWasmProcess(opts) {
23924
24032
  const { promise: ready2, resolve: started } = readiness(opts.program.abi);
23925
24033
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
23926
- const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
24034
+ const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
23927
24035
  const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
23928
- if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header3, blocked2);
24036
+ if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header4, blocked2);
23929
24037
  const threadSignals = /* @__PURE__ */ new Map();
23930
24038
  const created4 = new Created();
23931
24039
  const process = new WasmProcess(
@@ -23933,7 +24041,7 @@ function spawnWasmProcess(opts) {
23933
24041
  opts.fds,
23934
24042
  processOptions(
23935
24043
  opts,
23936
- header3,
24044
+ header4,
23937
24045
  {
23938
24046
  raise: (sig, info) => signal(sig, info),
23939
24047
  threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig),
@@ -23946,7 +24054,7 @@ function spawnWasmProcess(opts) {
23946
24054
  created4
23947
24055
  )
23948
24056
  );
23949
- publishStops(process, header3);
24057
+ publishStops(process, header4);
23950
24058
  const holds2 = new HeldPaths();
23951
24059
  opts.held?.add(holds2);
23952
24060
  const token = holdingToken(opts, holds2, {
@@ -23967,7 +24075,7 @@ function spawnWasmProcess(opts) {
23967
24075
  dispatch: clocks.timed(void 0, dispatch2)
23968
24076
  });
23969
24077
  const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
23970
- const jsThreads = jsThreadsOf(opts, process, token, dispatch2, clocks, header3);
24078
+ const jsThreads = jsThreadsOf(opts, process, token, dispatch2, clocks, header4);
23971
24079
  const { promise: exited, resolve: settle3 } = Promise.withResolvers();
23972
24080
  let done5 = false;
23973
24081
  const crash = new CrashSlot((message3) => crashReport(process, opts.onError, message3));
@@ -24066,7 +24174,7 @@ function spawnWasmProcess(opts) {
24066
24174
  );
24067
24175
  const terminate = (code, sig) => {
24068
24176
  if (opts.program.abi !== "wasi" || done5) finish(code, sig);
24069
- else dying.start(code, sig, header3, process, () => finish(code, sig));
24177
+ else dying.start(code, sig, header4, process, () => finish(code, sig));
24070
24178
  };
24071
24179
  const signal = (sig, info) => {
24072
24180
  if (process.signal(sig, info) === "terminate")
@@ -24081,16 +24189,16 @@ function spawnWasmProcess(opts) {
24081
24189
  signal,
24082
24190
  termsig: () => endedBy,
24083
24191
  onState: (listener) => process.onState(listener),
24084
- memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
24085
- ...processViews(process, opts, header3),
24192
+ memory: () => Atomics.load(header4, SAB_I_MEMORY) * 65536,
24193
+ ...processViews(process, opts, header4),
24086
24194
  writesBack: () => opts.program.abi === "wasi" && !done5,
24087
24195
  ...clockViews(clocks)
24088
24196
  };
24089
24197
  }
24090
- function jsThreadsOf(opts, process, token, dispatch2, clocks, header3) {
24198
+ function jsThreadsOf(opts, process, token, dispatch2, clocks, header4) {
24091
24199
  if (opts.program.abi !== "js") return void 0;
24092
24200
  const wakes = /* @__PURE__ */ new Set();
24093
- asyncFanout.set(header3, wakes);
24201
+ asyncFanout.set(header4, wakes);
24094
24202
  const threads = new JsThreads({
24095
24203
  wakes,
24096
24204
  cap: jsThreadCap(opts.env),
@@ -24105,10 +24213,10 @@ function jsThreadsOf(opts, process, token, dispatch2, clocks, header3) {
24105
24213
  process.onState((state) => threads.stopped(state === "stopped"));
24106
24214
  return threads;
24107
24215
  }
24108
- function processViews(process, opts, header3) {
24216
+ function processViews(process, opts, header4) {
24109
24217
  return {
24110
24218
  ignoredSignals: (fork) => process.inheritable(fork),
24111
- blockedSignals: () => opts.program.abi === "wasi" ? loadBlocked(header3) : [0, 0],
24219
+ blockedSignals: () => opts.program.abi === "wasi" ? loadBlocked(header4) : [0, 0],
24112
24220
  signalMasks: () => process.signalMasks(),
24113
24221
  umask: () => process.umask,
24114
24222
  cred: () => copyCred(process.cred)
@@ -24666,42 +24774,398 @@ function isMessage(data) {
24666
24774
  return adopt !== null && Array.isArray(adopt.records) && Array.isArray(adopt.flocks);
24667
24775
  }
24668
24776
 
24669
- // src/kernel/net/hosts-file.ts
24670
- var HOSTS_PATH = "/etc/hosts";
24671
- function parseHosts(text) {
24672
- const table = /* @__PURE__ */ new Map();
24673
- for (const raw2 of text.split("\n")) {
24674
- const [address, ...names2] = raw2.replace(/#.*/, "").trim().split(/\s+/);
24675
- if (!address || names2.length === 0) continue;
24676
- if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
24677
- for (const name2 of names2) {
24678
- const key = name2.toLowerCase().replace(/\.$/, "");
24679
- const known = table.get(key) ?? [];
24680
- if (!known.includes(address)) known.push(address);
24681
- table.set(key, known);
24777
+ // src/kernel/net/dns-stub.ts
24778
+ var DNS_PORT = 53;
24779
+ var DNS_STUB_ADDRESS = "127.0.0.53";
24780
+ var RESOLV_CONF_PATH = "/etc/resolv.conf";
24781
+ var RESOLV_CONF = `nameserver ${DNS_STUB_ADDRESS}
24782
+ options edns0
24783
+ `;
24784
+ var DNS_STUB_TTL = 30;
24785
+ var DNS_FORWARD_TIMEOUT_MS = 5e3;
24786
+ var DNS_TCP_IDLE_MS = 1e4;
24787
+ var DNS_TCP_MAX = 64;
24788
+ var DNS_UDP_INFLIGHT = 64;
24789
+ var TYPE_A = 1;
24790
+ var TYPE_PTR = 12;
24791
+ var TYPE_AAAA = 28;
24792
+ var TYPE_OPT = 41;
24793
+ var CLASS_IN = 1;
24794
+ var NOERROR = 0;
24795
+ var FORMERR = 1;
24796
+ var SERVFAIL = 2;
24797
+ var NXDOMAIN = 3;
24798
+ var NOTIMP = 4;
24799
+ var QR = 32768;
24800
+ var AA = 1024;
24801
+ var TC = 512;
24802
+ var RD = 256;
24803
+ var RA = 128;
24804
+ var CD = 16;
24805
+ var UDP_PLAIN = 512;
24806
+ var UDP_EDNS = 1232;
24807
+ var UDP_MAX = 4096;
24808
+ var DOH_MAX = 65535;
24809
+ var LOCAL_ZONES = ["localhost", "slicc.internal"];
24810
+ var MESSAGE = "application/dns-message";
24811
+ var u16 = (b, at) => b[at] << 8 | b[at + 1];
24812
+ function skipName(b, at) {
24813
+ let i = at;
24814
+ for (let hops = 0; hops < 128; hops++) {
24815
+ if (i >= b.length) return void 0;
24816
+ const len = b[i];
24817
+ if (len === 0) return i + 1;
24818
+ if ((len & 192) === 192) return i + 2 <= b.length ? i + 2 : void 0;
24819
+ if (len & 192) return void 0;
24820
+ i += len + 1;
24821
+ }
24822
+ return void 0;
24823
+ }
24824
+ function readName(b, at) {
24825
+ const labels = [];
24826
+ let i = at;
24827
+ let size = 0;
24828
+ for (; ; ) {
24829
+ if (i >= b.length) return void 0;
24830
+ const len = b[i];
24831
+ if (len === 0) break;
24832
+ if (len & 192) return void 0;
24833
+ size += len + 1;
24834
+ if (size > 254 || i + 1 + len > b.length) return void 0;
24835
+ labels.push(new TextDecoder().decode(b.subarray(i + 1, i + 1 + len)));
24836
+ i += len + 1;
24837
+ }
24838
+ return { name: labels.join(".").toLowerCase(), end: i + 1 };
24839
+ }
24840
+ function parseQuery(b) {
24841
+ if (b.length < 12) return void 0;
24842
+ const id2 = u16(b, 0);
24843
+ const flags2 = u16(b, 2);
24844
+ if (flags2 & QR) return void 0;
24845
+ if (flags2 >> 11 & 15) return { ok: false, id: id2, flags: flags2, rcode: NOTIMP };
24846
+ if (u16(b, 4) !== 1) return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24847
+ const read = readName(b, 12);
24848
+ if (!read || read.end + 4 > b.length) return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24849
+ const type = u16(b, read.end);
24850
+ const klass = u16(b, read.end + 2);
24851
+ const end = read.end + 4;
24852
+ let edns;
24853
+ let at = end;
24854
+ const records = u16(b, 6) + u16(b, 8) + u16(b, 10);
24855
+ for (let n = 0; n < records; n++) {
24856
+ const after = skipName(b, at);
24857
+ if (after === void 0 || after + 10 > b.length)
24858
+ return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24859
+ if (u16(b, after) === TYPE_OPT) edns = Math.max(UDP_PLAIN, u16(b, after + 2));
24860
+ at = after + 10 + u16(b, after + 8);
24861
+ if (at > b.length) return { ok: false, id: id2, flags: flags2, rcode: FORMERR };
24862
+ }
24863
+ return { ok: true, question: { id: id2, flags: flags2, name: read.name, type, klass, end, edns } };
24864
+ }
24865
+ function encodeName(name2) {
24866
+ const out = [];
24867
+ for (const label of name2.split(".").filter(Boolean)) {
24868
+ const bytes = new TextEncoder().encode(label);
24869
+ out.push(bytes.length, ...bytes);
24870
+ }
24871
+ out.push(0);
24872
+ return out;
24873
+ }
24874
+ function header2(id2, flags2, counts) {
24875
+ const out = [id2 >> 8, id2 & 255, flags2 >> 8, flags2 & 255];
24876
+ for (const c of counts) out.push(c >> 8, c & 255);
24877
+ return out;
24878
+ }
24879
+ function opt() {
24880
+ return [0, 0, TYPE_OPT, UDP_EDNS >> 8, UDP_EDNS & 255, 0, 0, 0, 0, 0, 0];
24881
+ }
24882
+ function record(type, rdata) {
24883
+ const ttl = DNS_STUB_TTL;
24884
+ return [
24885
+ 192,
24886
+ 12,
24887
+ type >> 8,
24888
+ type & 255,
24889
+ 0,
24890
+ CLASS_IN,
24891
+ ttl >>> 24 & 255,
24892
+ ttl >>> 16 & 255,
24893
+ ttl >>> 8 & 255,
24894
+ ttl & 255,
24895
+ rdata.length >> 8,
24896
+ rdata.length & 255,
24897
+ ...rdata
24898
+ ];
24899
+ }
24900
+ function replyFlags(query, rcode, aa) {
24901
+ return QR | query & 30720 | (aa ? AA : 0) | query & RD | RA | query & CD | rcode;
24902
+ }
24903
+ function answers(reply, q) {
24904
+ if (reply.length < 12 || !(u16(reply, 2) & QR) || u16(reply, 4) !== 1) return false;
24905
+ const read = readName(reply, 12);
24906
+ if (!read || read.end + 4 > reply.length) return false;
24907
+ return read.name === q.name && u16(reply, read.end) === q.type && u16(reply, read.end + 2) === q.klass;
24908
+ }
24909
+ function errorReply(id2, flags2, rcode) {
24910
+ return new Uint8Array(header2(id2, replyFlags(flags2, rcode, false), [0, 0, 0, 0]));
24911
+ }
24912
+ function answerReply(query, q, rcode, answers2, aa) {
24913
+ const extra = q.edns !== void 0 ? [opt()] : [];
24914
+ return new Uint8Array([
24915
+ ...header2(q.id, replyFlags(q.flags, rcode, aa), [1, answers2.length, 0, extra.length]),
24916
+ ...query.subarray(12, q.end),
24917
+ ...answers2.flat(),
24918
+ ...extra.flat()
24919
+ ]);
24920
+ }
24921
+ function truncated(reply, q, query) {
24922
+ const limit = q.edns !== void 0 ? Math.min(q.edns, UDP_MAX) : UDP_PLAIN;
24923
+ if (reply.length <= limit) return reply;
24924
+ const flags2 = u16(reply, 2) | TC;
24925
+ const extra = q.edns !== void 0 ? [opt()] : [];
24926
+ return new Uint8Array([
24927
+ ...header2(q.id, flags2, [1, 0, 0, extra.length]),
24928
+ ...query.subarray(12, q.end),
24929
+ ...extra.flat()
24930
+ ]);
24931
+ }
24932
+ function ipv6Text(groups) {
24933
+ return groups.map((g) => g.toString(16)).join(":");
24934
+ }
24935
+ function reverseAddress(name2) {
24936
+ if (name2.endsWith(".in-addr.arpa")) {
24937
+ const parts2 = name2.slice(0, -".in-addr.arpa".length).split(".");
24938
+ if (parts2.length !== 4) return void 0;
24939
+ const text = parts2.reverse().join(".");
24940
+ return ipv4Bytes(text) ? text.split(".").map(Number).join(".") : void 0;
24941
+ }
24942
+ if (name2.endsWith(".ip6.arpa")) {
24943
+ const nibbles = name2.slice(0, -".ip6.arpa".length).split(".");
24944
+ if (nibbles.length !== 32 || !nibbles.every((n) => /^[0-9a-f]$/.test(n))) return void 0;
24945
+ const hex4 = nibbles.reverse().join("");
24946
+ const groups = Array.from(
24947
+ { length: 8 },
24948
+ (_, i) => Number.parseInt(hex4.slice(i * 4, i * 4 + 4), 16)
24949
+ );
24950
+ return ipv6Text(groups);
24951
+ }
24952
+ return void 0;
24953
+ }
24954
+ function local(name2) {
24955
+ return LOCAL_ZONES.some((zone) => name2 === zone || name2.endsWith(`.${zone}`));
24956
+ }
24957
+ function literal(name2) {
24958
+ return ipv4Bytes(name2) !== void 0 || ipv6Groups(name2) !== void 0;
24959
+ }
24960
+ function addressData(address, type) {
24961
+ if (type === TYPE_A) return ipv4Bytes(address);
24962
+ const groups = type === TYPE_AAAA ? ipv6Groups(address) : void 0;
24963
+ return groups?.flatMap((g) => [g >> 8, g & 255]);
24964
+ }
24965
+ var DnsStub = class {
24966
+ resolver;
24967
+ forwarder;
24968
+ timeoutMs;
24969
+ constructor(options) {
24970
+ this.resolver = options.resolver;
24971
+ this.forwarder = options.forward;
24972
+ this.timeoutMs = options.timeoutMs ?? DNS_FORWARD_TIMEOUT_MS;
24973
+ }
24974
+ async answer(query, udp) {
24975
+ const parsed2 = parseQuery(query);
24976
+ if (!parsed2) return void 0;
24977
+ if (!parsed2.ok) return errorReply(parsed2.id, parsed2.flags, parsed2.rcode);
24978
+ const q = parsed2.question;
24979
+ const reply = await this.reply(query, q).catch(
24980
+ () => answerReply(query, q, SERVFAIL, [], false)
24981
+ );
24982
+ return udp ? truncated(reply, q, query) : reply;
24983
+ }
24984
+ async reply(query, q) {
24985
+ if (q.klass !== CLASS_IN || literal(q.name)) return this.forward(query, q);
24986
+ if (q.type === TYPE_PTR) {
24987
+ const address = reverseAddress(q.name);
24988
+ const name2 = address !== void 0 ? await this.reverse(address) : void 0;
24989
+ if (name2 !== void 0)
24990
+ return answerReply(query, q, NOERROR, [record(TYPE_PTR, encodeName(name2))], true);
24991
+ return this.forward(query, q);
24992
+ }
24993
+ if (q.type === TYPE_A || q.type === TYPE_AAAA) {
24994
+ const addresses = q.name === "" ? [] : await this.lookup(q.name);
24995
+ const answers2 = addresses.flatMap((a) => {
24996
+ const data = addressData(a, q.type);
24997
+ return data ? [record(q.type, data)] : [];
24998
+ });
24999
+ if (answers2.length > 0 || local(q.name) || await this.known(q.name)) {
25000
+ const rcode = addresses.length > 0 ? NOERROR : NXDOMAIN;
25001
+ return answerReply(query, q, rcode, answers2, local(q.name));
25002
+ }
25003
+ return this.forward(query, q);
25004
+ }
25005
+ if (await this.known(q.name)) return answerReply(query, q, NOERROR, [], true);
25006
+ if (local(q.name)) {
25007
+ const there = (await this.lookup(q.name)).length > 0;
25008
+ return answerReply(query, q, there ? NOERROR : NXDOMAIN, [], true);
24682
25009
  }
25010
+ return this.forward(query, q);
24683
25011
  }
24684
- return table;
25012
+ lookup(name2) {
25013
+ return this.resolver.resolve(name2, 0).catch(() => []);
25014
+ }
25015
+ known(name2) {
25016
+ return this.resolver.known(name2).catch(() => false);
25017
+ }
25018
+ reverse(address) {
25019
+ return this.resolver.reverse(address).catch(() => void 0);
25020
+ }
25021
+ async forward(query, q) {
25022
+ if (!this.forwarder) return answerReply(query, q, SERVFAIL, [], false);
25023
+ const asked = query.slice();
25024
+ asked[0] = 0;
25025
+ asked[1] = 0;
25026
+ const got = await this.forwarder(asked, AbortSignal.timeout(this.timeoutMs)).catch(
25027
+ () => void 0
25028
+ );
25029
+ if (!got || !answers(got, q)) return answerReply(query, q, SERVFAIL, [], false);
25030
+ const reply = got.slice();
25031
+ reply[0] = q.id >> 8;
25032
+ reply[1] = q.id & 255;
25033
+ return reply;
25034
+ }
25035
+ };
25036
+ async function collect(body, max) {
25037
+ const parts2 = [];
25038
+ let size = 0;
25039
+ for await (const part of body) {
25040
+ size += part.length;
25041
+ if (size > max) return void 0;
25042
+ parts2.push(part);
25043
+ }
25044
+ const out = new Uint8Array(size);
25045
+ let at = 0;
25046
+ for (const part of parts2) {
25047
+ out.set(part, at);
25048
+ at += part.length;
25049
+ }
25050
+ return out;
24685
25051
  }
24686
- function hostsReader(fs, path = HOSTS_PATH) {
24687
- let stamp = "";
24688
- let table;
24689
- return async () => {
24690
- const st = await fs.stat(path).catch(() => void 0);
24691
- if (!st?.isFile) {
24692
- stamp = "";
24693
- table = void 0;
25052
+ function dohForward(transport, url) {
25053
+ return async (query, signal) => {
25054
+ const res = await transport.fetch({
25055
+ url,
25056
+ method: "POST",
25057
+ headers: [
25058
+ ["content-type", MESSAGE],
25059
+ ["accept", MESSAGE]
25060
+ ],
25061
+ body: query,
25062
+ signal
25063
+ });
25064
+ const type = res.headers.find(([k]) => k.toLowerCase() === "content-type")?.[1] ?? "";
25065
+ if (res.status !== 200 || type.split(";")[0].trim().toLowerCase() !== MESSAGE) {
25066
+ await res.cancel().catch(() => void 0);
24694
25067
  return void 0;
24695
25068
  }
24696
- const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
24697
- if (now === stamp && table) return table;
24698
- const text = await fs.readFile(path).catch(() => void 0);
24699
- if (text === void 0) return void 0;
24700
- stamp = now;
24701
- table = parseHosts(text);
24702
- return table;
25069
+ return collect(res.body, DOH_MAX);
25070
+ };
25071
+ }
25072
+ function uplinkForward(uplink, server) {
25073
+ return async (query, signal) => {
25074
+ const conn = await uplink.dial({ network: "tcp", host: server, port: DNS_PORT, signal });
25075
+ const stop = () => conn.close();
25076
+ signal.addEventListener("abort", stop, { once: true });
25077
+ try {
25078
+ await conn.write(new Uint8Array([query.length >> 8, query.length & 255, ...query]));
25079
+ let got = new Uint8Array();
25080
+ for (; ; ) {
25081
+ if (got.length >= 2 && got.length >= 2 + u16(got, 0)) return got.slice(2, 2 + u16(got, 0));
25082
+ const piece = await conn.read();
25083
+ if (!piece) return void 0;
25084
+ const next3 = new Uint8Array(got.length + piece.length);
25085
+ next3.set(got);
25086
+ next3.set(piece, got.length);
25087
+ got = next3;
25088
+ }
25089
+ } finally {
25090
+ signal.removeEventListener("abort", stop);
25091
+ conn.close();
25092
+ }
24703
25093
  };
24704
25094
  }
25095
+ function dnsForward(uplink, transport, doh) {
25096
+ const server = uplink?.nameserver;
25097
+ if (uplink && server && (ipv4Bytes(server) || ipv6Groups(server)))
25098
+ return uplinkForward(uplink, server);
25099
+ return typeof doh === "string" ? dohForward(transport, doh) : void 0;
25100
+ }
25101
+ function kernelDnsStub(resolver, transport, uplink, doh) {
25102
+ return new DnsStub({ resolver, forward: dnsForward(uplink, transport, doh) });
25103
+ }
25104
+ async function readExactly(conn, size, signal) {
25105
+ const out = new Uint8Array(size);
25106
+ let at = 0;
25107
+ while (at < size) {
25108
+ const piece = await conn.read(size - at, signal);
25109
+ if (piece.length === 0) return void 0;
25110
+ out.set(piece, at);
25111
+ at += piece.length;
25112
+ }
25113
+ return out;
25114
+ }
25115
+ async function serveTcp(stub, conn) {
25116
+ try {
25117
+ for (; ; ) {
25118
+ const idle2 = AbortSignal.timeout(DNS_TCP_IDLE_MS);
25119
+ const size = await readExactly(conn, 2, idle2);
25120
+ if (!size) return;
25121
+ const query = await readExactly(conn, u16(size, 0), idle2);
25122
+ if (!query) return;
25123
+ const reply = await stub.answer(query, false);
25124
+ if (!reply) return;
25125
+ const framed = new Uint8Array([reply.length >> 8, reply.length & 255, ...reply]);
25126
+ const sent = await conn.write(framed, AbortSignal.timeout(DNS_TCP_IDLE_MS));
25127
+ if (sent < framed.length) return;
25128
+ }
25129
+ } catch {
25130
+ return;
25131
+ } finally {
25132
+ conn.close();
25133
+ }
25134
+ }
25135
+ function enableDnsStub(net, stub) {
25136
+ const at = { family: "inet", host: "127.0.0.1", port: DNS_PORT };
25137
+ net.reserve(DNS_PORT);
25138
+ net.kernelOnly(DNS_PORT, true);
25139
+ net.activate(at, () => {
25140
+ const listener = net.listen(at);
25141
+ const open2 = /* @__PURE__ */ new Set();
25142
+ void (async () => {
25143
+ for (; ; ) {
25144
+ const conn = await listener.accept().catch(() => void 0);
25145
+ if (!conn) return;
25146
+ if (open2.size >= DNS_TCP_MAX) {
25147
+ conn.close();
25148
+ continue;
25149
+ }
25150
+ open2.add(conn);
25151
+ void serveTcp(stub, conn).finally(() => open2.delete(conn));
25152
+ }
25153
+ })();
25154
+ });
25155
+ let inflight = 0;
25156
+ net.serveDgram(DNS_PORT, (datagram2, to) => {
25157
+ if (inflight >= DNS_UDP_INFLIGHT) return;
25158
+ inflight++;
25159
+ void stub.answer(datagram2.bytes, true).then(
25160
+ (reply) => {
25161
+ if (!reply) return;
25162
+ const from = { family: "inet", host: to.host, port: DNS_PORT };
25163
+ net.deliverDgram(datagram2.from.port, { bytes: reply, from });
25164
+ },
25165
+ () => void 0
25166
+ ).finally(() => inflight--);
25167
+ });
25168
+ }
24705
25169
 
24706
25170
  // src/kernel/net/redirect-hops.ts
24707
25171
  var HELD_MS = 3e4;
@@ -24709,13 +25173,13 @@ var HELD_MAX = 64;
24709
25173
  var HELD_PER_OWNER = 8;
24710
25174
  var MATCHED = ["range", "if-none-match", "if-modified-since", "if-range", "accept-encoding"];
24711
25175
  var KERNEL = -1;
24712
- function header2(headers, name2) {
25176
+ function header3(headers, name2) {
24713
25177
  const values = headers.filter(([n]) => n.toLowerCase() === name2).map(([, v]) => v);
24714
25178
  return values.length > 0 ? values.join(", ") : void 0;
24715
25179
  }
24716
25180
  function fingerprint(headers) {
24717
- const fields = MATCHED.map((name2) => header2(headers, name2) ?? "");
24718
- return JSON.stringify([...fields, header2(headers, "authorization") !== void 0]);
25181
+ const fields = MATCHED.map((name2) => header3(headers, name2) ?? "");
25182
+ return JSON.stringify([...fields, header3(headers, "authorization") !== void 0]);
24719
25183
  }
24720
25184
  function unauthorized(print) {
24721
25185
  return JSON.stringify([...JSON.parse(print).slice(0, -1), false]);
@@ -24758,7 +25222,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
24758
25222
  };
24759
25223
  const replay = (chain2) => {
24760
25224
  const [hop, ...rest2] = chain2.hops;
24761
- const location = hop && header2(hop.headers, "location");
25225
+ const location = hop && header3(hop.headers, "location");
24762
25226
  if (!hop || location === void 0) return chain2.final;
24763
25227
  const target = new URL(location, hop.url);
24764
25228
  target.hash = "";
@@ -24883,7 +25347,7 @@ function materializable(req) {
24883
25347
  if (req.shellGrants !== true && !isStrings(req.names)) return false;
24884
25348
  return isStrings(req.argv) && typeof req.path === "string" && typeof req.cwd === "string";
24885
25349
  }
24886
- function errorReply(code, message3) {
25350
+ function errorReply2(code, message3) {
24887
25351
  return { v: 1, error: { code, message: message3 } };
24888
25352
  }
24889
25353
  function isRecord(value2) {
@@ -24895,9 +25359,9 @@ function serialized(reply) {
24895
25359
  const text = JSON.stringify(reply);
24896
25360
  plain3 = text === void 0 ? void 0 : JSON.parse(text);
24897
25361
  } catch (err) {
24898
- return JSON.stringify(errorReply("EIO", lineOf2(err)));
25362
+ return JSON.stringify(errorReply2("EIO", lineOf2(err)));
24899
25363
  }
24900
- if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
25364
+ if (!isRecord(plain3)) return JSON.stringify(errorReply2("EIO", "the vault gave no reply"));
24901
25365
  const { v: _, ...rest2 } = plain3;
24902
25366
  return JSON.stringify({ v: 1, ...rest2 });
24903
25367
  }
@@ -24945,18 +25409,18 @@ var SealedChannel = class {
24945
25409
  }
24946
25410
  async answer(req, signal) {
24947
25411
  const hook = this.broker.hook;
24948
- if (!hook) return errorReply("ENOTCONN", "no vault is connected");
25412
+ if (!hook) return errorReply2("ENOTCONN", "no vault is connected");
24949
25413
  const stopped = new Promise((resolve2) => {
24950
25414
  signal.addEventListener("abort", () => resolve2(void 0), { once: true });
24951
25415
  });
24952
25416
  if (signal.aborted) return void 0;
24953
25417
  const asked = Promise.resolve().then(() => hook(req, { signal })).then(
24954
- (reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
24955
- (err) => errorReply("EIO", lineOf2(err))
25418
+ (reply2) => isRecord(reply2) ? reply2 : errorReply2("EIO", "the vault gave no reply"),
25419
+ (err) => errorReply2("EIO", lineOf2(err))
24956
25420
  );
24957
25421
  const reply = await Promise.race([asked, stopped]);
24958
25422
  if (!signal.aborted) return reply;
24959
- return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
25423
+ return signal.reason === "timeout" ? errorReply2("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
24960
25424
  }
24961
25425
  drop() {
24962
25426
  this.reply?.fill(0);
@@ -27302,6 +27766,10 @@ function blobModuleUrl(source) {
27302
27766
  const url = URL.createObjectURL(new Blob([source], { type: "text/javascript" }));
27303
27767
  return { url, revoke: () => URL.revokeObjectURL(url) };
27304
27768
  }
27769
+ function describe(req, tty) {
27770
+ const exe = req.exe === void 0 ? {} : { exe: req.exe };
27771
+ return { argv: [req.argv0, ...req.args], tty, started: Date.now(), ...exe };
27772
+ }
27305
27773
  function linksOf2(req) {
27306
27774
  return req.links === void 0 ? {} : { links: req.links };
27307
27775
  }
@@ -27323,6 +27791,7 @@ var LAYOUT = [
27323
27791
  ["/etc", 493],
27324
27792
  [PASSWD, 420],
27325
27793
  [GROUP, 420],
27794
+ [RESOLV_CONF_PATH, 420],
27326
27795
  ["/usr", 493],
27327
27796
  ["/usr/local", 493]
27328
27797
  ];
@@ -27665,6 +28134,10 @@ var Launcher = class {
27665
28134
  roots: packageTlsRoots(this.verifiedFs(options.fs), this.modulesDir),
27666
28135
  ca: this.ca
27667
28136
  });
28137
+ enableDnsStub(
28138
+ this.net,
28139
+ kernelDnsStub(this.resolver, this.transport, options.uplink, options.doh)
28140
+ );
27668
28141
  enableCdp(this.net, this.cdp);
27669
28142
  this.facades.enable(this.net);
27670
28143
  const fs = this.commandFs(this.base);
@@ -27752,10 +28225,10 @@ var Launcher = class {
27752
28225
  ready: () => this.fstab,
27753
28226
  lookup: (name2) => this.users.lookup(name2),
27754
28227
  watch: async (paths, notify) => {
27755
- const local = this.watchers.watch(paths, { recursive: true }, () => notify());
28228
+ const local2 = this.watchers.watch(paths, { recursive: true }, () => notify());
27756
28229
  const remote = await this.watchFiles(paths, notify);
27757
28230
  return () => {
27758
- local();
28231
+ local2();
27759
28232
  remote();
27760
28233
  };
27761
28234
  },
@@ -27941,7 +28414,7 @@ var Launcher = class {
27941
28414
  abi: "wasi",
27942
28415
  glue,
27943
28416
  wasm: glue,
27944
- argv0: baseName2(argv0 || file).replace(/\.wasm$/, ""),
28417
+ argv0,
27945
28418
  ...asked
27946
28419
  };
27947
28420
  }
@@ -28483,7 +28956,18 @@ var Launcher = class {
28483
28956
  const handle = await this.admitted(
28484
28957
  program.abi !== "js",
28485
28958
  req.fds,
28486
- (fds, quietOom) => this.start({ ...req, fds, quietOom, cwd, program, argv0: target.argv0, args, env, cwdSlot })
28959
+ (fds, quietOom) => this.start({
28960
+ ...req,
28961
+ fds,
28962
+ quietOom,
28963
+ cwd,
28964
+ program,
28965
+ argv0: target.argv0,
28966
+ exe: target.copy ?? target.glue,
28967
+ args,
28968
+ env,
28969
+ cwdSlot
28970
+ })
28487
28971
  ).finally(() => this.cwds.release(cwdSlot));
28488
28972
  void handle.exited.finally(done5);
28489
28973
  return handle;
@@ -28675,11 +29159,7 @@ var Launcher = class {
28675
29159
  if (req.pgid !== void 0) this.jobs.join(pid, req.pgid);
28676
29160
  if (req.group === "lead") this.jobs.lead(pid);
28677
29161
  if (req.group === "session") this.jobs.setsid(pid);
28678
- this.described.set(pid, {
28679
- argv: [req.argv0, ...req.args],
28680
- tty: terminal?.name ?? null,
28681
- started: Date.now()
28682
- });
29162
+ this.described.set(pid, describe(req, terminal?.name ?? null));
28683
29163
  handle.onState(
28684
29164
  (state) => state === "stopped" ? this.stopped.add(pid) : this.stopped.delete(pid)
28685
29165
  );
@@ -29287,6 +29767,19 @@ var Launcher = class {
29287
29767
  inUse(path) {
29288
29768
  return [...this.openFiles].some((nodes) => nodes.holds(path)) || heldUnder(this.held, path);
29289
29769
  }
29770
+ async resolvConf() {
29771
+ if (isProtected(this.prefixes, RESOLV_CONF_PATH)) return;
29772
+ try {
29773
+ const there = await this.base.lstat(RESOLV_CONF_PATH).then(
29774
+ () => true,
29775
+ () => false
29776
+ );
29777
+ if (there) return;
29778
+ await this.base.writeFile(RESOLV_CONF_PATH, RESOLV_CONF);
29779
+ } catch {
29780
+ return;
29781
+ }
29782
+ }
29290
29783
  async stampLayout() {
29291
29784
  const layout = [
29292
29785
  ...LAYOUT,
@@ -29422,6 +29915,7 @@ var Launcher = class {
29422
29915
  await this.mountShm();
29423
29916
  await this.pnpmReady();
29424
29917
  await this.users.ensure();
29918
+ await this.resolvConf();
29425
29919
  if (this.owners) await this.stampLayout();
29426
29920
  if (this.owners) await this.sudoer.provision();
29427
29921
  await writeCaFile(this.base, this.ca).catch(() => void 0);
@@ -29660,12 +30154,12 @@ var Launcher = class {
29660
30154
  const out = [];
29661
30155
  const err = [];
29662
30156
  const keep2 = options.collect !== false;
29663
- const collect = (chunks, tee) => (bytes) => {
30157
+ const collect2 = (chunks, tee) => (bytes) => {
29664
30158
  if (keep2) chunks.push(bytes);
29665
30159
  tee?.(bytes);
29666
30160
  };
29667
- const stdout = collect(out, options.onStdout);
29668
- const stderr = collect(err, options.onStderr);
30161
+ const stdout = collect2(out, options.onStdout);
30162
+ const stderr = collect2(err, options.onStderr);
29669
30163
  const report = (message3) => stderr(encoder10.encode(`${message3}
29670
30164
  `));
29671
30165
  if (!planned) {
@@ -30083,7 +30577,14 @@ function facadesOption(req, port) {
30083
30577
  function remotes(port, req) {
30084
30578
  return {
30085
30579
  ...req.transport ? { transport: new RemoteTransport(port, req.transport) } : {},
30086
- ...req.uplink ? { uplink: new RemoteUplink(port, req.uplink.traits, req.uplink.routes) } : {}
30580
+ ...req.uplink ? {
30581
+ uplink: new RemoteUplink(
30582
+ port,
30583
+ req.uplink.traits,
30584
+ req.uplink.routes,
30585
+ req.uplink.nameserver
30586
+ )
30587
+ } : {}
30087
30588
  };
30088
30589
  }
30089
30590
  function dial(l, req) {
@@ -30181,6 +30682,7 @@ function hostOptions(req, port, sealed, clipboard, lookup2) {
30181
30682
  return {
30182
30683
  cron: { lock: `slicc-kernel-cron:${req.metadata ?? META_DB}` },
30183
30684
  ...req.hostname !== void 0 ? { hostname: req.hostname } : {},
30685
+ ...req.doh !== void 0 ? { doh: req.doh } : {},
30184
30686
  ...req.users !== void 0 ? { users: req.users } : {},
30185
30687
  ...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
30186
30688
  ...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},