@ai-ecoverse/slicc-kernel 1.111.0 → 1.112.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.
package/README.md CHANGED
@@ -432,7 +432,7 @@ The kernel has one node name, `slicc` unless `createKernel({ hostname })` (or `c
432
432
  - **What `uname` says:** for an Emscripten program built with homescoop's `__syscall_uname` import (wasm-coreutils 9.12.0-7 on), the kernel answers `uname(2)`: sysname `Linux`, nodename the node name, release `6.0.0-slicc` (as `/proc/sys/kernel/osrelease`), version `#1 SMP PREEMPT_DYNAMIC` (as `/proc/version`), machine `wasm32` and domainname `(none)`, so `uname -a` and musl's `gethostname()` see them. `uname -o` is coreutils' compiled-in `Emscripten`. Older Emscripten builds still report their C library's `Emscripten 4.0.23` and `emscripten`, and WASIX programs `wasmer.sh`; the kernel has nothing to answer there.
433
433
  - **Resolving it:** `/etc/hosts` maps the node name and both of those names to `127.0.1.1` (Debian's convention), and name resolution answers them, and `localhost.localdomain`, itself, as `127.0.1.1` and `::1`. So a program that looks up its own host name, as git does for every commit, never asks the [uplink](#uplink), and `127.0.1.1` is the kernel's loopback.
434
434
  - **The trade-off:** a raw connection to the real `wasmer.sh` resolves to loopback too. HTTP(S) to it still goes through the realm proxy and the transport, which resolve names themselves; `wasmer.sh` is deliberately not in `no_proxy`.
435
- - **A real file wins:** a root that has its own `/etc/hostname` (or `/etc/hosts`, `/etc/passwd`) keeps it, and programs read that file rather than the synthetic one. The kernel's name still drives `HOSTNAME` and name resolution. A program that opens one of these synthetic files for writing (as root, since `/etc` is root's) gets a real one first: a root-owned `0644` copy of the defaults. So `echo '10.0.0.9 db' >> /etc/hosts` keeps `localhost` and the other default entries, `>` replaces them as on Linux, and `rm` returns to the synthetic file. The copy is `0644` whatever the umask. Programs that read `/etc/hosts` themselves (WASIX/musl ones, such as python's `socket.gethostbyname`) resolve an added name. The kernel's own resolver, which Emscripten programs, `ctx.net` and HTTP through the transport use, doesn't read the file yet ([#898](https://github.com/ai-ecoverse/slicc-kernel/issues/898)).
435
+ - **A real file wins:** a root that has its own `/etc/hostname` (or `/etc/hosts`, `/etc/passwd`) keeps it, and programs read that file rather than the synthetic one. The kernel's name still drives `HOSTNAME` and name resolution. A program that opens one of these synthetic files for writing (as root, since `/etc` is root's) gets a real one first: a root-owned `0644` copy of the defaults. So `echo '10.0.0.9 db' >> /etc/hosts` keeps `localhost` and the other default entries, `>` replaces them as on Linux, and `rm` returns to the synthetic file. The copy is `0644` whatever the umask. Programs that read `/etc/hosts` themselves (WASIX/musl ones, such as python's `socket.gethostbyname`) resolve an added name. So does the kernel's own resolver, which Emscripten programs' `getaddrinfo`, WASIX `resolve` and `ctx.net` use ([#898](https://github.com/ai-ecoverse/slicc-kernel/issues/898)). It reads a real `/etc/hosts` as glibc does (`#` comments, aliases, IPv4 and IPv6, first entries first), re-reads it when its inode, size or mtime change, and answers a name the file lists before its built-in names. HTTP that goes through the transport by URL is resolved there, so `curl http://db/` doesn't use the file.
436
436
 
437
437
  ### Uplink
438
438
 
@@ -6192,7 +6192,7 @@ function satisfies(version, range2) {
6192
6192
  }
6193
6193
 
6194
6194
  // src/version.ts
6195
- var KERNEL_VERSION = true ? "1.111.0" : "0.0.0-dev";
6195
+ var KERNEL_VERSION = true ? "1.112.0" : "0.0.0-dev";
6196
6196
  var OS_RELEASE = "6.0.0-slicc";
6197
6197
  function procVersion() {
6198
6198
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -14706,6 +14706,7 @@ var Resolver = class {
14706
14706
  own;
14707
14707
  cache = /* @__PURE__ */ new Map();
14708
14708
  pending = /* @__PURE__ */ new Map();
14709
+ hosts;
14709
14710
  constructor(options) {
14710
14711
  this.uplink = options.uplink;
14711
14712
  this.routes = options.routes;
@@ -14713,6 +14714,14 @@ var Resolver = class {
14713
14714
  this.timeoutMs = options.timeoutMs ?? RESOLVE_TIMEOUT_MS;
14714
14715
  this.log = options.log ?? ((message3) => console.warn(message3));
14715
14716
  this.own = ownNames(options.hostname ?? DEFAULT_HOSTNAME);
14717
+ this.hosts = options.hosts;
14718
+ }
14719
+ async fromFile(key, family) {
14720
+ const listed = (await this.hosts?.().catch(() => void 0))?.get(key);
14721
+ if (!listed) return void 0;
14722
+ const v4 = listed.filter((a) => ipv4Bytes(a) !== void 0);
14723
+ const v6 = listed.filter((a) => ipv4Bytes(a) === void 0);
14724
+ return family === 4 ? v4 : family === 6 ? v6 : [...v4, ...v6];
14716
14725
  }
14717
14726
  async resolve(name2, family, blocking) {
14718
14727
  const key = name2.toLowerCase().replace(/\.$/, "");
@@ -14721,6 +14730,8 @@ var Resolver = class {
14721
14730
  const v4 = family !== 6 && local ? [local] : [];
14722
14731
  return family === 4 ? v4 : [...v4, key];
14723
14732
  }
14733
+ const listed = this.hosts ? await this.fromFile(key, family) : void 0;
14734
+ if (listed?.length) return listed;
14724
14735
  if (local) {
14725
14736
  const six = loopbackName(key, this.own) ? ["::1"] : [];
14726
14737
  return family === 6 ? six : family === 4 ? [local] : [local, ...six];
@@ -19122,6 +19133,43 @@ var JobTable = class {
19122
19133
  }
19123
19134
  };
19124
19135
 
19136
+ // src/kernel/net/hosts-file.ts
19137
+ var HOSTS_PATH = "/etc/hosts";
19138
+ function parseHosts(text) {
19139
+ const table = /* @__PURE__ */ new Map();
19140
+ for (const raw of text.split("\n")) {
19141
+ const [address, ...names] = raw.replace(/#.*/, "").trim().split(/\s+/);
19142
+ if (!address || names.length === 0) continue;
19143
+ if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
19144
+ for (const name2 of names) {
19145
+ const key = name2.toLowerCase().replace(/\.$/, "");
19146
+ const known = table.get(key) ?? [];
19147
+ if (!known.includes(address)) known.push(address);
19148
+ table.set(key, known);
19149
+ }
19150
+ }
19151
+ return table;
19152
+ }
19153
+ function hostsReader(fs, path = HOSTS_PATH) {
19154
+ let stamp = "";
19155
+ let table;
19156
+ return async () => {
19157
+ const st = await fs.stat(path).catch(() => void 0);
19158
+ if (!st?.isFile) {
19159
+ stamp = "";
19160
+ table = void 0;
19161
+ return void 0;
19162
+ }
19163
+ const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
19164
+ if (now === stamp && table) return table;
19165
+ const text = await fs.readFile(path).catch(() => void 0);
19166
+ if (text === void 0) return void 0;
19167
+ stamp = now;
19168
+ table = parseHosts(text);
19169
+ return table;
19170
+ };
19171
+ }
19172
+
19125
19173
  // src/kernel/net/redirect-hops.ts
19126
19174
  var HELD_MS = 3e4;
19127
19175
  var HELD_MAX = 64;
@@ -22494,7 +22542,12 @@ var Launcher = class {
22494
22542
  this.uplink = options.uplink;
22495
22543
  this.routes = new Routes(options.uplink?.traits.ipv6 === true);
22496
22544
  if (options.uplink?.routes) this.routes.set(options.uplink.routes);
22497
- this.resolver = new Resolver({ uplink: options.uplink, routes: this.routes, hostname });
22545
+ this.resolver = new Resolver({
22546
+ uplink: options.uplink,
22547
+ routes: this.routes,
22548
+ hostname,
22549
+ hosts: hostsReader(this.base)
22550
+ });
22498
22551
  if (options.uplink) this.net.useUplink({ uplink: options.uplink, routes: this.routes });
22499
22552
  enableNetwork(this.net, {
22500
22553
  transport: this.transport,