@lakutata/netif 0.0.0-stage → 3.1.4

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 (93) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +299 -2
  3. package/README.zh-CN.md +229 -0
  4. package/binding.gyp +43 -0
  5. package/dist/cjs/exceptions/NetIfException.d.ts +17 -0
  6. package/dist/cjs/exceptions/NetIfException.js +24 -0
  7. package/dist/cjs/exceptions/NetIfNotEnforcedException.d.ts +12 -0
  8. package/dist/cjs/exceptions/NetIfNotEnforcedException.js +19 -0
  9. package/dist/cjs/exceptions/NetIfNotFoundException.d.ts +12 -0
  10. package/dist/cjs/exceptions/NetIfNotFoundException.js +19 -0
  11. package/dist/cjs/exceptions/NetIfNotSupportedException.d.ts +12 -0
  12. package/dist/cjs/exceptions/NetIfNotSupportedException.js +19 -0
  13. package/dist/cjs/exceptions/NetIfTimeoutException.d.ts +11 -0
  14. package/dist/cjs/exceptions/NetIfTimeoutException.js +18 -0
  15. package/dist/cjs/exports/Netif.d.ts +11 -0
  16. package/dist/cjs/exports/Netif.js +26 -0
  17. package/dist/cjs/lib/Addon.d.ts +5 -0
  18. package/dist/cjs/lib/Addon.js +9 -0
  19. package/dist/cjs/lib/Attachment.d.ts +152 -0
  20. package/dist/cjs/lib/Attachment.js +415 -0
  21. package/dist/cjs/lib/Enforcement.d.ts +22 -0
  22. package/dist/cjs/lib/Enforcement.js +45 -0
  23. package/dist/cjs/lib/Functions.d.ts +66 -0
  24. package/dist/cjs/lib/Functions.js +97 -0
  25. package/dist/cjs/lib/InterfaceListener.d.ts +92 -0
  26. package/dist/cjs/lib/InterfaceListener.js +99 -0
  27. package/dist/cjs/lib/InterfaceUDPSocket.d.ts +119 -0
  28. package/dist/cjs/lib/InterfaceUDPSocket.js +245 -0
  29. package/dist/cjs/lib/Internal.d.ts +10 -0
  30. package/dist/cjs/lib/Internal.js +9 -0
  31. package/dist/cjs/lib/Native.d.ts +54 -0
  32. package/dist/cjs/lib/Native.js +83 -0
  33. package/dist/cjs/lib/NetworkInterface.d.ts +313 -0
  34. package/dist/cjs/lib/NetworkInterface.js +391 -0
  35. package/dist/cjs/lib/Registry.d.ts +26 -0
  36. package/dist/cjs/lib/Registry.js +103 -0
  37. package/dist/cjs/lib/Snapshot.d.ts +17 -0
  38. package/dist/cjs/lib/Snapshot.js +84 -0
  39. package/dist/cjs/lib/Types.d.ts +63 -0
  40. package/dist/cjs/lib/Types.js +2 -0
  41. package/dist/cjs/package.json +1 -0
  42. package/dist/esm/exceptions/NetIfException.js +20 -0
  43. package/dist/esm/exceptions/NetIfNotEnforcedException.js +15 -0
  44. package/dist/esm/exceptions/NetIfNotFoundException.js +15 -0
  45. package/dist/esm/exceptions/NetIfNotSupportedException.js +15 -0
  46. package/dist/esm/exceptions/NetIfTimeoutException.js +14 -0
  47. package/dist/esm/exports/Netif.js +9 -0
  48. package/dist/esm/lib/Addon.js +10 -0
  49. package/dist/esm/lib/Attachment.js +410 -0
  50. package/dist/esm/lib/Enforcement.js +41 -0
  51. package/dist/esm/lib/Functions.js +92 -0
  52. package/dist/esm/lib/InterfaceListener.js +95 -0
  53. package/dist/esm/lib/InterfaceUDPSocket.js +241 -0
  54. package/dist/esm/lib/Internal.js +6 -0
  55. package/dist/esm/lib/Native.js +75 -0
  56. package/dist/esm/lib/NetworkInterface.js +386 -0
  57. package/dist/esm/lib/Registry.js +100 -0
  58. package/dist/esm/lib/Snapshot.js +79 -0
  59. package/dist/esm/lib/Types.js +1 -0
  60. package/dist/types/exceptions/NetIfException.d.ts +17 -0
  61. package/dist/types/exceptions/NetIfNotEnforcedException.d.ts +12 -0
  62. package/dist/types/exceptions/NetIfNotFoundException.d.ts +12 -0
  63. package/dist/types/exceptions/NetIfNotSupportedException.d.ts +12 -0
  64. package/dist/types/exceptions/NetIfTimeoutException.d.ts +11 -0
  65. package/dist/types/exports/Netif.d.ts +11 -0
  66. package/dist/types/lib/Addon.d.ts +5 -0
  67. package/dist/types/lib/Attachment.d.ts +152 -0
  68. package/dist/types/lib/Enforcement.d.ts +22 -0
  69. package/dist/types/lib/Functions.d.ts +66 -0
  70. package/dist/types/lib/InterfaceListener.d.ts +92 -0
  71. package/dist/types/lib/InterfaceUDPSocket.d.ts +119 -0
  72. package/dist/types/lib/Internal.d.ts +10 -0
  73. package/dist/types/lib/Native.d.ts +54 -0
  74. package/dist/types/lib/NetworkInterface.d.ts +313 -0
  75. package/dist/types/lib/Registry.d.ts +26 -0
  76. package/dist/types/lib/Snapshot.d.ts +17 -0
  77. package/dist/types/lib/Types.d.ts +63 -0
  78. package/native/Interfaces.cpp +34 -0
  79. package/native/Interfaces.h +47 -0
  80. package/native/Sockets.h +36 -0
  81. package/native/Watcher.h +27 -0
  82. package/native/addon.cpp +195 -0
  83. package/native/darwin/Interfaces.cpp +150 -0
  84. package/native/darwin/Sockets.cpp +44 -0
  85. package/native/darwin/Watcher.cpp +113 -0
  86. package/native/linux/Interfaces.cpp +133 -0
  87. package/native/linux/RouteNetlink.h +38 -0
  88. package/native/linux/Sockets.cpp +89 -0
  89. package/native/linux/Watcher.cpp +70 -0
  90. package/native/windows/Interfaces.cpp +78 -0
  91. package/native/windows/Sockets.cpp +56 -0
  92. package/native/windows/Watcher.cpp +53 -0
  93. package/package.json +81 -4
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nativeList = nativeList;
4
+ exports.nativeWatch = nativeWatch;
5
+ exports.nativeUnwatch = nativeUnwatch;
6
+ exports.nativeBindSocket = nativeBindSocket;
7
+ exports.nativeMembership = nativeMembership;
8
+ exports.nativeWeakReception = nativeWeakReception;
9
+ const node_util_1 = require("node:util");
10
+ const Addon_js_1 = require("./Addon.js");
11
+ const NetIfException_js_1 = require("../exceptions/NetIfException.js");
12
+ /**
13
+ * The error of a call of the addon as an exception of the package: the code of the error of the system as its `errno`
14
+ * (the name of the POSIX error, the number of the Windows one)
15
+ */
16
+ function exception(error) {
17
+ if (!(error instanceof Error))
18
+ return new NetIfException_js_1.NetIfException(String(error));
19
+ const thrown = new NetIfException_js_1.NetIfException(error.message, { cause: error });
20
+ const number = error.errno;
21
+ if (typeof number === 'number') {
22
+ if (process.platform === 'win32') {
23
+ thrown.errno = number;
24
+ }
25
+ else {
26
+ try {
27
+ thrown.errno = (0, node_util_1.getSystemErrorName)(-number);
28
+ }
29
+ catch {
30
+ thrown.errno = number;
31
+ }
32
+ }
33
+ }
34
+ return thrown;
35
+ }
36
+ /**
37
+ * Calls a function of the addon, its errors turned into exceptions of the package
38
+ */
39
+ function call(run) {
40
+ try {
41
+ return run(Addon_js_1.addon);
42
+ }
43
+ catch (error) {
44
+ throw exception(error);
45
+ }
46
+ }
47
+ /**
48
+ * The interfaces of the machine as the addon reads them
49
+ */
50
+ function nativeList() {
51
+ return call((functions) => functions.list());
52
+ }
53
+ /**
54
+ * Starts the notifications of the changes of the interfaces: changed() called at each one (once by thread)
55
+ */
56
+ function nativeWatch(changed) {
57
+ call((functions) => functions.watch(changed));
58
+ }
59
+ /**
60
+ * Stops the notifications
61
+ */
62
+ function nativeUnwatch() {
63
+ call((functions) => functions.unwatch());
64
+ }
65
+ /**
66
+ * A socket bound to the interface of the name (Linux): its descriptor and port
67
+ */
68
+ function nativeBindSocket(name, family, stream, port, backlog) {
69
+ return call((functions) => functions.bindSocket(name, family, stream, port, backlog));
70
+ }
71
+ /**
72
+ * The socket of the descriptor joins or leaves the multicast group on the interface of the index (Linux)
73
+ */
74
+ function nativeMembership(fd, group, index, join) {
75
+ call((functions) => functions.membership(fd, group, index, join));
76
+ }
77
+ /**
78
+ * The setting that makes the system accept, through another interface, the packets for the addresses of the interface of
79
+ * the index; null when it refuses them (the strong host model of Windows and macOS)
80
+ */
81
+ function nativeWeakReception(index, family) {
82
+ return call((functions) => functions.weakReception(index, family));
83
+ }
@@ -0,0 +1,313 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { type Server } from 'node:net';
3
+ import { InterfaceListener, type ListenOptions } from './InterfaceListener.js';
4
+ import { InterfaceUDPSocket, type UDPSocketOptions } from './InterfaceUDPSocket.js';
5
+ import { OBSERVE, type Observer } from './Internal.js';
6
+ import { type InterfaceAddress, type NetworkInterfaceInfo } from './Types.js';
7
+ /**
8
+ * How an interface is given: its name (`'eth1'`, `'en0'`, `'以太网 2'`), its hardware address (`{mac: '52:54:00:12:34:56'}`,
9
+ * the same on every system, the one to give a management port by) or its index (`{index: 3}`, which changes when the
10
+ * interface is unplugged and plugged again).
11
+ */
12
+ export type InterfaceSelector = string | {
13
+ /**
14
+ * The hardware address: `'52:54:00:12:34:56'`, `'52-54-00-12-34-56'`, in either case.
15
+ */
16
+ mac: string;
17
+ } | {
18
+ /**
19
+ * The index of the interface.
20
+ */
21
+ index: number;
22
+ };
23
+ /**
24
+ * A change of the addresses of an interface: the `change` event.
25
+ */
26
+ export interface AddressChange {
27
+ /**
28
+ * Every usable address of the interface now.
29
+ */
30
+ addresses: InterfaceAddress[];
31
+ /**
32
+ * The addresses that came: added, or usable since (an IPv6 address once its duplicate address detection is over).
33
+ */
34
+ added: InterfaceAddress[];
35
+ /**
36
+ * The addresses that went.
37
+ */
38
+ removed: InterfaceAddress[];
39
+ }
40
+ /**
41
+ * The options of `waitForAddress()`.
42
+ */
43
+ export interface WaitForAddressOptions {
44
+ /**
45
+ * The family of the address to wait for, any by default.
46
+ */
47
+ family?: 'IPv4' | 'IPv6';
48
+ /**
49
+ * The milliseconds to wait at most, without limit by default: then a `NetIfTimeoutException`.
50
+ */
51
+ timeout?: number;
52
+ }
53
+ /**
54
+ * The options of `bindSocket()`.
55
+ */
56
+ export interface BindSocketOptions {
57
+ /**
58
+ * The port, 0 by default: one the system chooses (`port` of the result).
59
+ */
60
+ port?: number;
61
+ /**
62
+ * The family of the socket, `'IPv4'` by default. An IPv6 socket is IPv6 only.
63
+ */
64
+ family?: 'IPv4' | 'IPv6';
65
+ /**
66
+ * `'tcp'` (a listening socket, by default) or `'udp'`.
67
+ */
68
+ type?: 'tcp' | 'udp';
69
+ /**
70
+ * The length of the queue of the connections not accepted yet of a TCP socket, 511 by default.
71
+ */
72
+ backlog?: number;
73
+ }
74
+ /**
75
+ * A socket bound to an interface: `bindSocket()`.
76
+ */
77
+ export interface BoundSocket {
78
+ /**
79
+ * Its file descriptor, to give to `server.listen({fd})` (a `net.Server`) or `socket.bind({fd})` (a `dgram` socket),
80
+ * which then own it; closed by `fs.closeSync(fd)` when it is not given.
81
+ */
82
+ fd: number;
83
+ /**
84
+ * Its port.
85
+ */
86
+ port: number;
87
+ /**
88
+ * Its family.
89
+ */
90
+ family: 'IPv4' | 'IPv6';
91
+ /**
92
+ * Its type.
93
+ */
94
+ type: 'tcp' | 'udp';
95
+ }
96
+ /**
97
+ * The events of a `NetworkInterface` and their arguments.
98
+ */
99
+ export interface NetworkInterfaceEvents {
100
+ /**
101
+ * The addresses changed (some added, some removed).
102
+ */
103
+ change: [change: AddressChange];
104
+ /**
105
+ * The link came up: a cable plugged in, an association made.
106
+ */
107
+ up: [];
108
+ /**
109
+ * The link went down.
110
+ */
111
+ down: [];
112
+ /**
113
+ * The interface appeared: plugged, created, enabled (on Windows).
114
+ */
115
+ added: [];
116
+ /**
117
+ * The interface disappeared.
118
+ */
119
+ removed: [];
120
+ }
121
+ /**
122
+ * What changed between two states of an interface: whether it appeared or disappeared, its link came up or went down,
123
+ * and its addresses added and removed
124
+ */
125
+ export declare function changesOf(previous: NetworkInterfaceInfo | undefined, next: NetworkInterfaceInfo | undefined): {
126
+ appeared: boolean;
127
+ disappeared: boolean;
128
+ up: boolean;
129
+ down: boolean;
130
+ added: InterfaceAddress[];
131
+ removed: InterfaceAddress[];
132
+ };
133
+ /**
134
+ * A network interface of the machine, followed: its state and addresses now, events when they change, and the servers
135
+ * listening on it. The interface may not exist yet (a USB adapter not plugged in, a system starting): the object follows
136
+ * it once it appears, and again when it is unplugged and plugged back.
137
+ * @example
138
+ * ```typescript
139
+ * import {type InterfaceAddress, NetworkInterface} from '@lakutata/netif'
140
+ *
141
+ * const management: NetworkInterface = new NetworkInterface('eth1')
142
+ * console.log(management.present, management.running, management.addresses.map(address => address.address))
143
+ * management.on('change', ({added, removed}) => console.log('added', added, 'removed', removed))
144
+ * management.on('down', () => console.log('the cable of eth1 is unplugged'))
145
+ * const address: InterfaceAddress = await management.waitForAddress({family: 'IPv4', timeout: 30000})
146
+ * console.log(`http://${address.address}:8080`)
147
+ * management.close()
148
+ * ```
149
+ */
150
+ export declare class NetworkInterface extends EventEmitter<NetworkInterfaceEvents> {
151
+ #private;
152
+ /**
153
+ * How the interface was given.
154
+ */
155
+ readonly selector: InterfaceSelector;
156
+ /**
157
+ * Follows an interface.
158
+ * @param selector Its name, `{mac}` or `{index}`.
159
+ * @throws NetIfNotFoundException An index that no interface has (an index is never given again once its interface is
160
+ * gone), or a hardware address that several interfaces have now (a bridge and its ports: give the name then).
161
+ */
162
+ constructor(selector: InterfaceSelector);
163
+ /**
164
+ * The network interfaces of the machine, as `listInterfaces()` gives them.
165
+ * @returns The interfaces, in the order of the system.
166
+ * @example
167
+ * ```typescript
168
+ * import {NetworkInterface} from '@lakutata/netif'
169
+ *
170
+ * const names: string[] = NetworkInterface.list().map(entry => entry.name)
171
+ * ```
172
+ */
173
+ static list(): NetworkInterfaceInfo[];
174
+ /**
175
+ * Whether the interface exists now.
176
+ */
177
+ get present(): boolean;
178
+ /**
179
+ * Its name, `undefined` while it does not exist.
180
+ */
181
+ get name(): string | undefined;
182
+ /**
183
+ * Its index, `undefined` while it does not exist. It changes when the interface is unplugged and plugged again.
184
+ */
185
+ get index(): number | undefined;
186
+ /**
187
+ * Its hardware address, `undefined` while it does not exist or when it has none (and on the macOS versions that hide
188
+ * it).
189
+ */
190
+ get mac(): string | undefined;
191
+ /**
192
+ * Whether it is enabled (its administrative state); `false` while it does not exist.
193
+ */
194
+ get up(): boolean;
195
+ /**
196
+ * Whether its link is up (a cable plugged in, an association made); `false` while it does not exist.
197
+ */
198
+ get running(): boolean;
199
+ /**
200
+ * Whether it is the loopback interface.
201
+ */
202
+ get loopback(): boolean;
203
+ /**
204
+ * Its usable addresses now, an empty array when it has none or does not exist.
205
+ */
206
+ get addresses(): InterfaceAddress[];
207
+ /**
208
+ * Its state now as `listInterfaces()` gives it, `undefined` while it does not exist.
209
+ */
210
+ get info(): NetworkInterfaceInfo | undefined;
211
+ /**
212
+ * Whether the object was closed.
213
+ */
214
+ get closed(): boolean;
215
+ /**
216
+ * An address of the interface: one it has now, or the first one it gets.
217
+ * @param options The family of the address and the milliseconds to wait at most.
218
+ * @returns The address.
219
+ * @throws NetIfTimeoutException No address came in time.
220
+ * @throws NetIfException The object was closed while waiting.
221
+ * @example
222
+ * ```typescript
223
+ * import {type InterfaceAddress, NetworkInterface} from '@lakutata/netif'
224
+ *
225
+ * const wan: NetworkInterface = new NetworkInterface('eth0')
226
+ * const address: InterfaceAddress = await wan.waitForAddress({family: 'IPv4', timeout: 60000})
227
+ * wan.close()
228
+ * ```
229
+ */
230
+ waitForAddress(options?: WaitForAddressOptions): Promise<InterfaceAddress>;
231
+ /**
232
+ * Listens on the interface for the server: its connections are accepted by the listener returned and given to the
233
+ * server, which handles them as its own. On Linux the sockets are bound to the interface (whatever its addresses, the
234
+ * system refuses the connections coming through another interface); on Windows and macOS each address of the
235
+ * interface is listened on, and listened on again when they change (`enforced` tells whether the system refuses the
236
+ * connections coming through another interface). The interface may not exist yet, nor have an address: it is listened
237
+ * on once it can be, and again when it is unplugged and plugged back.
238
+ * @param server A `net.Server` or a server built on one: `http`, `https`, `http2`, `tls`; for Express
239
+ * `createServer(app)`, for Fastify `fastify.server`. The server itself must not listen.
240
+ * @param options The port, the families, `strict` and the backlog.
241
+ * @returns The listener, once the interface is listened on (or waited for).
242
+ * @throws NetIfNotEnforcedException With `strict`, where the system cannot refuse the connections coming through
243
+ * another interface.
244
+ * @throws NetIfException The system refused the first listening, its code as `errno` (`'EADDRINUSE'`, `'EACCES'`…).
245
+ * Later refusals are `error` events of the listener, and retried.
246
+ * @example
247
+ * ```typescript
248
+ * import {createServer} from 'node:http'
249
+ * import express from 'express'
250
+ * import {type InterfaceListener, NetworkInterface} from '@lakutata/netif'
251
+ *
252
+ * const app = express()
253
+ * app.get('/', (request, response) => response.send('ok'))
254
+ * const management: NetworkInterface = new NetworkInterface({mac: '52:54:00:12:34:56'})
255
+ * const listener: InterfaceListener = await management.listen(createServer(app), {port: 8080})
256
+ * listener.on('error', error => console.error(error))
257
+ * ```
258
+ */
259
+ listen(server: Server, options: ListenOptions): Promise<InterfaceListener>;
260
+ /**
261
+ * A UDP socket of the interface, with the methods and the events of a `dgram` socket. On Linux it is bound to the
262
+ * interface: it receives what comes through it, broadcasts and the multicast of the groups joined there included,
263
+ * whatever its addresses. On Windows and macOS a socket is bound to each address of the interface (on macOS it
264
+ * receives no broadcast nor multicast then). It is bound again when the addresses change and when the interface is
265
+ * plugged back.
266
+ * @param options The port, the families and `strict`.
267
+ * @returns The socket, once it is bound (or the interface waited for).
268
+ * @throws NetIfNotEnforcedException With `strict`, where the system cannot refuse the datagrams coming through
269
+ * another interface.
270
+ * @throws NetIfException The system refused the first binding, its code as `errno`.
271
+ * @example
272
+ * ```typescript
273
+ * import {type InterfaceUDPSocket, NetworkInterface} from '@lakutata/netif'
274
+ *
275
+ * const socket: InterfaceUDPSocket = await new NetworkInterface('eth1').createUDPSocket({port: 9999, family: 'IPv4'})
276
+ * socket.setBroadcast(true)
277
+ * socket.on('message', (message, remote) => socket.send(message, remote.port, remote.address))
278
+ * ```
279
+ */
280
+ createUDPSocket(options: UDPSocketOptions): Promise<InterfaceUDPSocket>;
281
+ /**
282
+ * A socket bound to the interface (Linux, `SO_BINDTODEVICE`), on the port of every address of its family: it gets the
283
+ * connections and the datagrams that come through the interface, whatever the address they were sent to, and the
284
+ * system refuses the other ones. For the users that need the server itself listening (its `address()` and `close()`
285
+ * as usual): the socket is not made again when the interface is unplugged and plugged back, which `listen()` does.
286
+ * In Bun, give the descriptor to a `net.Server` or a `dgram` socket (Bun's `http.Server` does not listen on one).
287
+ * @param options The port, the family, the type and the backlog.
288
+ * @returns The descriptor of the socket and its port.
289
+ * @throws NetIfNotSupportedException Outside Linux: macOS and Windows have no socket bound to an interface.
290
+ * @throws NetIfNotFoundException The interface does not exist now.
291
+ * @throws NetIfNotEnforcedException The process may not bind a socket to an interface (CAP_NET_RAW before Linux 5.7).
292
+ * @throws NetIfException Another refusal of the system, its code as `errno` (`'EADDRINUSE'`…).
293
+ * @example
294
+ * ```typescript
295
+ * import {createServer} from 'node:http'
296
+ * import {type BoundSocket, NetworkInterface} from '@lakutata/netif'
297
+ *
298
+ * const management: NetworkInterface = new NetworkInterface('eth1')
299
+ * const socket: BoundSocket = management.bindSocket({port: 8080, family: 'IPv4', type: 'tcp'})
300
+ * createServer((request, response) => response.end('ok')).listen({fd: socket.fd})
301
+ * ```
302
+ */
303
+ bindSocket(options?: BindSocketOptions): BoundSocket;
304
+ /**
305
+ * Stops following the interface: no event any more; its listeners are closed, the waits of `waitForAddress()`
306
+ * rejected.
307
+ */
308
+ close(): void;
309
+ /**
310
+ * Internal: follows the readings of the interfaces (the listeners of the interface)
311
+ */
312
+ [OBSERVE](observer: Observer): () => void;
313
+ }