@planx.machina.at/tunnel 0.0.0-PLACEHOLDER

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.
Files changed (4) hide show
  1. package/README.md +89 -0
  2. package/index.d.ts +91 -0
  3. package/index.js +324 -0
  4. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @planx.machina.at/tunnel
2
+
3
+ TUN device + smoltcp userspace TCP/IP stack NAPI module for planx vnet (Pattern C privileged daemon).
4
+
5
+ ## Overview
6
+
7
+ Pattern C 分離 model の native side。 planx-networkd (= root process) が本 NAPI module を load
8
+ して TUN device + smoltcp Interface + tokio poll loop を起動する。 USER process side の
9
+ planx daemon は tRPC over unix socket で networkd に接続し、 L4 event のみ boundary を超える。
10
+
11
+ ## NAPI exports
12
+
13
+ - `setup_vnet({ selfHip, prefix, mtu })` → `{ ifaceName }`
14
+ - `addPeerAddress({ hipBytes })` / `removePeerAddress({ hipBytes })`
15
+ - `injectTcpData({ connId, payload })` / `injectTcpClose({ connId })` / `injectUdpSend({ dstPort, srcAddr, srcPort, payload })`
16
+ - `onEvent((ev: NetworkdEvent) => void)` / `offEvent()`
17
+
18
+ ## Dev build (single platform)
19
+
20
+ ```bash
21
+ nx build @planx.machina.at/tunnel # release .node (native target only)
22
+ nx build:debug @planx.machina.at/tunnel # debug .node
23
+ nx test @planx.machina.at/tunnel # cargo test
24
+ nx lint @planx.machina.at/tunnel # cargo clippy
25
+ ```
26
+
27
+ ## Release flow (5 platform fan-out + publish)
28
+
29
+ 5 per-arch package を repo commit して GAR publish するための flow。
30
+ **Mac local で実行する想定** (= CI では走らせない)。
31
+
32
+ ### Prerequisites
33
+
34
+ ```bash
35
+ brew install zig
36
+ rustup target add aarch64-apple-darwin x86_64-apple-darwin \
37
+ x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu \
38
+ x86_64-unknown-linux-musl
39
+ gcloud auth application-default login # or GOOGLE_APPLICATION_CREDENTIALS export
40
+ ```
41
+
42
+ ### Steps
43
+
44
+ ```bash
45
+ # 1. 5 platform 分の .node を prebuilt/ に生成
46
+ nx prebuild @planx.machina.at/tunnel
47
+
48
+ # 2. prebuilt/*.node を packages/@planx.machina.at/tunnel-{arch}/ に配布 +
49
+ # main package の index.js / index.d.ts を最新化
50
+ nx build @planx.machina.at/tunnel
51
+
52
+ # 3. (commit .node files to repo — Rust source 改修ごとに必要)
53
+ git add prebuilt/ ../../../packages/@planx.machina.at/tunnel-*/planx-tunnel.*.node
54
+ git commit -m "chore(tunnel): rebuild native binaries"
55
+
56
+ # 4. 全 publish (= main + 5 per-arch を tag:package run-many で publish)
57
+ nx run-many -t deploy -p 'tag:package' --parallel=2
58
+ ```
59
+
60
+ ### Dry run
61
+
62
+ ```bash
63
+ DRY_RUN=true nx run @planx.machina.at/tunnel:deploy
64
+ ```
65
+
66
+ ## Per-arch binaries
67
+
68
+ | Package | Platform | libc |
69
+ | ------------------------------------------------ | ---------------- | ---- |
70
+ | `@planx.machina.at/tunnel-darwin-arm64` | macOS Apple Silicon | - |
71
+ | `@planx.machina.at/tunnel-darwin-x64` | macOS Intel | - |
72
+ | `@planx.machina.at/tunnel-linux-x64-gnu` | Linux x86_64 | glibc |
73
+ | `@planx.machina.at/tunnel-linux-arm64-gnu` | Linux ARM64 | glibc |
74
+ | `@planx.machina.at/tunnel-linux-x64-musl` | Linux x86_64 | musl |
75
+
76
+ main `@planx.machina.at/tunnel` package が optionalDependencies で各 per-arch を参照し、
77
+ runtime に NAPI loader (`index.js`) が platform 判定で適切な `.node` を require する。
78
+
79
+ ## Troubleshooting
80
+
81
+ - **401/403 on publish** → ~/.npmrc の GAR token 切れ / 権限を確認。
82
+ CI では on-merge-to-develop.yml の "Configure Artifact Registry auth" step が token を
83
+ 供給する (deploy script 自身は auth しない、#4645 で npx auth-refresh を撤去)。
84
+ 手動で publish する場合のみ `npx google-artifactregistry-auth` で refresh する。
85
+ - **napi build で "linker `cc` not found"** (Linux cross-compile) →
86
+ `--zig` flag が抜けている。 `prebuild.sh` 経由で実行する。
87
+ - **`cargo: command not found`** → rustup PATH 未設定。
88
+ `export PATH="$HOME/.cargo/bin:$PATH"`。
89
+ - **prebuilt/*.node が古い** → `nx prebuild` を re-run して `git add` し直す。
package/index.d.ts ADDED
@@ -0,0 +1,91 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ /**
7
+ * L4 event。 tagged union (= JS では `type` field で discriminator)。
8
+ *
9
+ * Note: NAPI-RS は Rust enum を tagged union として直接 export できないため、
10
+ * flat struct + `event_type` 文字列 + 全 field optional の形にする (= 旧 PacketEvent 互換)。
11
+ */
12
+ export interface NetworkdEvent {
13
+ /**
14
+ * "tcp_open" | "tcp_data" | "tcp_fin" | "tcp_rst" | "udp_dgram" |
15
+ * "tun_open_ok" | "tun_open_error" | "iface_build_error" | "iface_ready"
16
+ */
17
+ eventType: string
18
+ /** connection id (TCP 系のみ、 UDP / 状態 event は 0)。 */
19
+ connId: bigint
20
+ /** dst port (tcp_open / udp_dgram で meaningful、 他は 0)。 */
21
+ dstPort: number
22
+ /** payload bytes (event_type に依存)。 */
23
+ payload: Buffer
24
+ /** 送信元 IPv6 address (16 bytes raw)。 L4 event で meaningful、 状態 event は 0 bytes。 */
25
+ srcAddr: Buffer
26
+ /** 送信元 port。 */
27
+ srcPort: number
28
+ /** 宛先 IPv6 address (16 bytes raw)。 tcp_* で meaningful。 */
29
+ dstAddr: Buffer
30
+ }
31
+ /**
32
+ * JS から渡された callback を global state に登録する。
33
+ *
34
+ * 1 callback / engine の制約 (旧 callback は overwrite される)。 poll loop は state から
35
+ * callback を都度 lock-load して呼ぶ。
36
+ */
37
+ export declare function onEvent(callback: (arg: NetworkdEvent) => any): void
38
+ /** global state から callback を解除する (= 以降の poll loop event は dropped)。 */
39
+ export declare function offEvent(): void
40
+ export declare function injectTcpData(input: InjectTcpDataInput): void
41
+ export declare function injectTcpClose(input: InjectTcpCloseInput): void
42
+ export declare function injectUdpSend(input: InjectUdpSendInput): void
43
+ export declare function addPeerAddress(input: PeerAddressInput): void
44
+ export declare function removePeerAddress(input: PeerAddressInput): void
45
+ export declare function addSelfAddress(input: AddSelfAddressInput): void
46
+ export declare function setupVnet(input: SetupVnetInput): SetupVnetOutput
47
+ /** setup_vnet input。 */
48
+ export interface SetupVnetInput {
49
+ /** 自端末 HIP (= ORCHID v2 IPv6 文字列、 例: "2001:2a:dead:beef:8000:abcd:1234:5678")。 */
50
+ selfHip: string
51
+ /** routing prefix 長 (推奨: 32 = ORCHID v2 prefix + planx OGA ID で peer space 全域)。 */
52
+ prefix: number
53
+ /** MTU (推奨: 1280 = IPv6 minimum)。 */
54
+ mtu: number
55
+ /** 任意で interface name (None なら OS 既定)。 */
56
+ interfaceName?: string
57
+ }
58
+ /** setup_vnet output。 */
59
+ export interface SetupVnetOutput {
60
+ /** OS が assign した実 interface name (= "utun9" 等)。 */
61
+ ifaceName: string
62
+ }
63
+ /** add_self_address input (P3: hip 単位 additive 登録)。 */
64
+ export interface AddSelfAddressInput {
65
+ /** 追加する自 hip (= ORCHID v2 IPv6 文字列)。 */
66
+ selfHip: string
67
+ }
68
+ /** add/remove_peer_address input。 */
69
+ export interface PeerAddressInput {
70
+ /** peer HIP IPv6 raw 16 byte buffer。 */
71
+ hipBytes: Buffer
72
+ }
73
+ /** inject_tcp_data input。 */
74
+ export interface InjectTcpDataInput {
75
+ connId: bigint
76
+ payload: Buffer
77
+ }
78
+ /** inject_tcp_close input。 */
79
+ export interface InjectTcpCloseInput {
80
+ connId: bigint
81
+ }
82
+ /** inject_udp_send input。 */
83
+ export interface InjectUdpSendInput {
84
+ dstPort: number
85
+ /** 送信元 IPv6 address (16 bytes raw、 = remote peer の HIP)。 */
86
+ srcAddr: Buffer
87
+ srcPort: number
88
+ payload: Buffer
89
+ }
90
+ /** crate version (Cargo.toml の `[package].version` を expose)。 sanity check 用。 */
91
+ export declare function version(): string
package/index.js ADDED
@@ -0,0 +1,324 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
7
+ const { existsSync, readFileSync } = require('fs')
8
+ const { join } = require('path')
9
+
10
+ const { platform, arch } = process
11
+
12
+ let nativeBinding = null
13
+ let localFileExisted = false
14
+ let loadError = null
15
+
16
+ function isMusl() {
17
+ // For Node 10
18
+ if (!process.report || typeof process.report.getReport !== 'function') {
19
+ try {
20
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
+ return readFileSync(lddPath, 'utf8').includes('musl')
22
+ } catch (e) {
23
+ return true
24
+ }
25
+ } else {
26
+ const { glibcVersionRuntime } = process.report.getReport().header
27
+ return !glibcVersionRuntime
28
+ }
29
+ }
30
+
31
+ switch (platform) {
32
+ case 'android':
33
+ switch (arch) {
34
+ case 'arm64':
35
+ localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node'))
36
+ try {
37
+ if (localFileExisted) {
38
+ nativeBinding = require('./index.android-arm64.node')
39
+ } else {
40
+ nativeBinding = require('@planx.machina.at/tunnel-android-arm64')
41
+ }
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ break
46
+ case 'arm':
47
+ localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node'))
48
+ try {
49
+ if (localFileExisted) {
50
+ nativeBinding = require('./index.android-arm-eabi.node')
51
+ } else {
52
+ nativeBinding = require('@planx.machina.at/tunnel-android-arm-eabi')
53
+ }
54
+ } catch (e) {
55
+ loadError = e
56
+ }
57
+ break
58
+ default:
59
+ throw new Error(`Unsupported architecture on Android ${arch}`)
60
+ }
61
+ break
62
+ case 'win32':
63
+ switch (arch) {
64
+ case 'x64':
65
+ localFileExisted = existsSync(
66
+ join(__dirname, 'index.win32-x64-msvc.node')
67
+ )
68
+ try {
69
+ if (localFileExisted) {
70
+ nativeBinding = require('./index.win32-x64-msvc.node')
71
+ } else {
72
+ nativeBinding = require('@planx.machina.at/tunnel-win32-x64-msvc')
73
+ }
74
+ } catch (e) {
75
+ loadError = e
76
+ }
77
+ break
78
+ case 'ia32':
79
+ localFileExisted = existsSync(
80
+ join(__dirname, 'index.win32-ia32-msvc.node')
81
+ )
82
+ try {
83
+ if (localFileExisted) {
84
+ nativeBinding = require('./index.win32-ia32-msvc.node')
85
+ } else {
86
+ nativeBinding = require('@planx.machina.at/tunnel-win32-ia32-msvc')
87
+ }
88
+ } catch (e) {
89
+ loadError = e
90
+ }
91
+ break
92
+ case 'arm64':
93
+ localFileExisted = existsSync(
94
+ join(__dirname, 'index.win32-arm64-msvc.node')
95
+ )
96
+ try {
97
+ if (localFileExisted) {
98
+ nativeBinding = require('./index.win32-arm64-msvc.node')
99
+ } else {
100
+ nativeBinding = require('@planx.machina.at/tunnel-win32-arm64-msvc')
101
+ }
102
+ } catch (e) {
103
+ loadError = e
104
+ }
105
+ break
106
+ default:
107
+ throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
+ }
109
+ break
110
+ case 'darwin':
111
+ localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node'))
112
+ try {
113
+ if (localFileExisted) {
114
+ nativeBinding = require('./index.darwin-universal.node')
115
+ } else {
116
+ nativeBinding = require('@planx.machina.at/tunnel-darwin-universal')
117
+ }
118
+ break
119
+ } catch {}
120
+ switch (arch) {
121
+ case 'x64':
122
+ localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node'))
123
+ try {
124
+ if (localFileExisted) {
125
+ nativeBinding = require('./index.darwin-x64.node')
126
+ } else {
127
+ nativeBinding = require('@planx.machina.at/tunnel-darwin-x64')
128
+ }
129
+ } catch (e) {
130
+ loadError = e
131
+ }
132
+ break
133
+ case 'arm64':
134
+ localFileExisted = existsSync(
135
+ join(__dirname, 'index.darwin-arm64.node')
136
+ )
137
+ try {
138
+ if (localFileExisted) {
139
+ nativeBinding = require('./index.darwin-arm64.node')
140
+ } else {
141
+ nativeBinding = require('@planx.machina.at/tunnel-darwin-arm64')
142
+ }
143
+ } catch (e) {
144
+ loadError = e
145
+ }
146
+ break
147
+ default:
148
+ throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
+ }
150
+ break
151
+ case 'freebsd':
152
+ if (arch !== 'x64') {
153
+ throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
+ }
155
+ localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node'))
156
+ try {
157
+ if (localFileExisted) {
158
+ nativeBinding = require('./index.freebsd-x64.node')
159
+ } else {
160
+ nativeBinding = require('@planx.machina.at/tunnel-freebsd-x64')
161
+ }
162
+ } catch (e) {
163
+ loadError = e
164
+ }
165
+ break
166
+ case 'linux':
167
+ switch (arch) {
168
+ case 'x64':
169
+ if (isMusl()) {
170
+ localFileExisted = existsSync(
171
+ join(__dirname, 'index.linux-x64-musl.node')
172
+ )
173
+ try {
174
+ if (localFileExisted) {
175
+ nativeBinding = require('./index.linux-x64-musl.node')
176
+ } else {
177
+ nativeBinding = require('@planx.machina.at/tunnel-linux-x64-musl')
178
+ }
179
+ } catch (e) {
180
+ loadError = e
181
+ }
182
+ } else {
183
+ localFileExisted = existsSync(
184
+ join(__dirname, 'index.linux-x64-gnu.node')
185
+ )
186
+ try {
187
+ if (localFileExisted) {
188
+ nativeBinding = require('./index.linux-x64-gnu.node')
189
+ } else {
190
+ nativeBinding = require('@planx.machina.at/tunnel-linux-x64-gnu')
191
+ }
192
+ } catch (e) {
193
+ loadError = e
194
+ }
195
+ }
196
+ break
197
+ case 'arm64':
198
+ if (isMusl()) {
199
+ localFileExisted = existsSync(
200
+ join(__dirname, 'index.linux-arm64-musl.node')
201
+ )
202
+ try {
203
+ if (localFileExisted) {
204
+ nativeBinding = require('./index.linux-arm64-musl.node')
205
+ } else {
206
+ nativeBinding = require('@planx.machina.at/tunnel-linux-arm64-musl')
207
+ }
208
+ } catch (e) {
209
+ loadError = e
210
+ }
211
+ } else {
212
+ localFileExisted = existsSync(
213
+ join(__dirname, 'index.linux-arm64-gnu.node')
214
+ )
215
+ try {
216
+ if (localFileExisted) {
217
+ nativeBinding = require('./index.linux-arm64-gnu.node')
218
+ } else {
219
+ nativeBinding = require('@planx.machina.at/tunnel-linux-arm64-gnu')
220
+ }
221
+ } catch (e) {
222
+ loadError = e
223
+ }
224
+ }
225
+ break
226
+ case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'index.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./index.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('@planx.machina.at/tunnel-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'index.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./index.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('@planx.machina.at/tunnel-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'index.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./index.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('@planx.machina.at/tunnel-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'index.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./index.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('@planx.machina.at/tunnel-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
285
+ localFileExisted = existsSync(
286
+ join(__dirname, 'index.linux-s390x-gnu.node')
287
+ )
288
+ try {
289
+ if (localFileExisted) {
290
+ nativeBinding = require('./index.linux-s390x-gnu.node')
291
+ } else {
292
+ nativeBinding = require('@planx.machina.at/tunnel-linux-s390x-gnu')
293
+ }
294
+ } catch (e) {
295
+ loadError = e
296
+ }
297
+ break
298
+ default:
299
+ throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
+ }
301
+ break
302
+ default:
303
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
+ }
305
+
306
+ if (!nativeBinding) {
307
+ if (loadError) {
308
+ throw loadError
309
+ }
310
+ throw new Error(`Failed to load native binding`)
311
+ }
312
+
313
+ const { onEvent, offEvent, injectTcpData, injectTcpClose, injectUdpSend, addPeerAddress, removePeerAddress, addSelfAddress, setupVnet, version } = nativeBinding
314
+
315
+ module.exports.onEvent = onEvent
316
+ module.exports.offEvent = offEvent
317
+ module.exports.injectTcpData = injectTcpData
318
+ module.exports.injectTcpClose = injectTcpClose
319
+ module.exports.injectUdpSend = injectUdpSend
320
+ module.exports.addPeerAddress = addPeerAddress
321
+ module.exports.removePeerAddress = removePeerAddress
322
+ module.exports.addSelfAddress = addSelfAddress
323
+ module.exports.setupVnet = setupVnet
324
+ module.exports.version = version
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@planx.machina.at/tunnel",
3
+ "version": "0.0.0-PLACEHOLDER",
4
+ "description": "TUN device + smoltcp userspace TCP/IP stack NAPI module for planx vnet (Pattern C privileged daemon)",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "homepage": "https://github.com/nontangent/x_x_machina/tree/develop/projects/@planx.machina.at/tunnel",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/nontangent/x_x_machina.git"
11
+ },
12
+ "license": "MIT",
13
+ "napi": {
14
+ "binaryName": "planx-tunnel",
15
+ "targets": [
16
+ "aarch64-apple-darwin",
17
+ "x86_64-apple-darwin",
18
+ "x86_64-unknown-linux-gnu",
19
+ "aarch64-unknown-linux-gnu",
20
+ "x86_64-unknown-linux-musl",
21
+ "x86_64-pc-windows-msvc"
22
+ ]
23
+ },
24
+ "scripts": {
25
+ "artifacts": "napi artifacts",
26
+ "build": "napi build --platform --release",
27
+ "build:debug": "napi build --platform",
28
+ "version": "napi version"
29
+ },
30
+ "devDependencies": {
31
+ "@napi-rs/cli": "^2.18.4"
32
+ },
33
+ "engines": {
34
+ "node": ">= 20"
35
+ },
36
+ "files": [
37
+ "index.js",
38
+ "index.d.ts",
39
+ "*.node"
40
+ ]
41
+ }