appium-ios-tuntap 0.1.3 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [0.1.5](https://github.com/appium/appium-ios-tuntap/compare/v0.1.4...v0.1.5) (2026-04-09)
2
+
3
+ ### Code Refactoring
4
+
5
+ * remove global signal handlers from library code ([6e267df](https://github.com/appium/appium-ios-tuntap/commit/6e267dffe1785acfcd57d431090e4cd4995bfa39))
6
+
7
+ ## [0.1.4](https://github.com/appium/appium-ios-tuntap/compare/v0.1.3...v0.1.4) (2026-04-08)
8
+
9
+ ### Bug Fixes
10
+
11
+ * replace exec with execFile to prevent shell injection ([9614041](https://github.com/appium/appium-ios-tuntap/commit/9614041375fb5f9edfcd14d6cf4c65b002f19e4a))
12
+
1
13
  ## [0.1.3](https://github.com/appium/appium-ios-tuntap/compare/v0.1.2...v0.1.3) (2026-01-28)
2
14
 
3
15
  ### Miscellaneous Chores
package/build/Makefile CHANGED
@@ -336,8 +336,8 @@ ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
336
336
  endif
337
337
 
338
338
  quiet_cmd_regen_makefile = ACTION Regenerating $@
339
- cmd_regen_makefile = cd $(srcdir); /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/runner/Library/Caches/node-gyp/24.13.0" "-Dnode_gyp_dir=/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/Users/runner/Library/Caches/node-gyp/24.13.0/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/build/config.gypi -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node/common.gypi "--toplevel-dir=." binding.gyp
340
- Makefile: $(srcdir)/../../../Library/Caches/node-gyp/24.13.0/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi $(srcdir)/node_modules/node-addon-api/node_api.gyp $(srcdir)/node_modules/npm/node_modules/node-gyp/addon.gypi
339
+ cmd_regen_makefile = cd $(srcdir); /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/runner/Library/Caches/node-gyp/24.14.1" "-Dnode_gyp_dir=/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/Users/runner/Library/Caches/node-gyp/24.14.1/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/build/config.gypi -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node/common.gypi "--toplevel-dir=." binding.gyp
340
+ Makefile: $(srcdir)/../../../Library/Caches/node-gyp/24.14.1/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi $(srcdir)/node_modules/node-addon-api/node_api.gyp $(srcdir)/node_modules/npm/node_modules/node-gyp/addon.gypi
341
341
  $(call do_cmd,regen_makefile)
342
342
 
343
343
  # "all" is a concatenation of the "all" targets from all the included
@@ -1,4 +1,4 @@
1
- cmd_Release/obj.target/nothing/node_modules/node-addon-api/nothing.o := cc -o Release/obj.target/nothing/node_modules/node-addon-api/nothing.o ../node_modules/node-addon-api/nothing.c '-DNODE_GYP_MODULE_NAME=nothing' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node -I/Users/runner/Library/Caches/node-gyp/24.13.0/src -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/config -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/openssl/include -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/uv/include -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/zlib -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/v8/include -O3 -gdwarf-2 -fno-strict-aliasing -mmacosx-version-min=13.5 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -MMD -MF ./Release/.deps/Release/obj.target/nothing/node_modules/node-addon-api/nothing.o.d.raw -c
1
+ cmd_Release/obj.target/nothing/node_modules/node-addon-api/nothing.o := cc -o Release/obj.target/nothing/node_modules/node-addon-api/nothing.o ../node_modules/node-addon-api/nothing.c '-DNODE_GYP_MODULE_NAME=nothing' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node -I/Users/runner/Library/Caches/node-gyp/24.14.1/src -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/config -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/openssl/include -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/uv/include -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/zlib -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/v8/include -O3 -gdwarf-2 -fno-strict-aliasing -mmacosx-version-min=13.5 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -MMD -MF ./Release/.deps/Release/obj.target/nothing/node_modules/node-addon-api/nothing.o.d.raw -c
2
2
  Release/obj.target/nothing/node_modules/node-addon-api/nothing.o: \
3
3
  ../node_modules/node-addon-api/nothing.c
4
4
  ../node_modules/node-addon-api/nothing.c:
@@ -1,29 +1,29 @@
1
- cmd_Release/obj.target/tuntap/src/tuntap.o := c++ -o Release/obj.target/tuntap/src/tuntap.o ../src/tuntap.cc '-DNODE_GYP_MODULE_NAME=tuntap' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_CPP_EXCEPTIONS' '-DNAPI_VERSION=8' '-DBUILDING_NODE_EXTENSION' -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node -I/Users/runner/Library/Caches/node-gyp/24.13.0/src -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/config -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/openssl/include -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/uv/include -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/zlib -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/v8/include -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api -O3 -gdwarf-2 -fno-strict-aliasing -mmacosx-version-min=10.15 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -Wall -Wextra -Wno-unused-parameter -Wno-vla-extension -Wno-error -std=c++17 -stdlib=libc++ -fno-rtti -O3 -fPIC -MMD -MF ./Release/.deps/Release/obj.target/tuntap/src/tuntap.o.d.raw -c
1
+ cmd_Release/obj.target/tuntap/src/tuntap.o := c++ -o Release/obj.target/tuntap/src/tuntap.o ../src/tuntap.cc '-DNODE_GYP_MODULE_NAME=tuntap' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DNAPI_CPP_EXCEPTIONS' '-DNAPI_VERSION=8' '-DBUILDING_NODE_EXTENSION' -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node -I/Users/runner/Library/Caches/node-gyp/24.14.1/src -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/config -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/openssl/include -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/uv/include -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/zlib -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/v8/include -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api -O3 -gdwarf-2 -fno-strict-aliasing -mmacosx-version-min=10.15 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -Wall -Wextra -Wno-unused-parameter -Wno-vla-extension -Wno-error -std=c++17 -stdlib=libc++ -fno-rtti -O3 -fPIC -MMD -MF ./Release/.deps/Release/obj.target/tuntap/src/tuntap.o.d.raw -c
2
2
  Release/obj.target/tuntap/src/tuntap.o: ../src/tuntap.cc \
3
3
  /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api/napi.h \
4
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/node_api.h \
5
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/js_native_api.h \
6
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/js_native_api_types.h \
7
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/node_api_types.h \
4
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/node_api.h \
5
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/js_native_api.h \
6
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/js_native_api_types.h \
7
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/node_api_types.h \
8
8
  /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api/napi-inl.h \
9
9
  /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api/napi-inl.deprecated.h \
10
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv.h \
11
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/errno.h \
12
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/version.h \
13
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/unix.h \
14
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/threadpool.h \
15
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/darwin.h
10
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv.h \
11
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/errno.h \
12
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/version.h \
13
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/unix.h \
14
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/threadpool.h \
15
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/darwin.h
16
16
  ../src/tuntap.cc:
17
17
  /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api/napi.h:
18
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/node_api.h:
19
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/js_native_api.h:
20
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/js_native_api_types.h:
21
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/node_api_types.h:
18
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/node_api.h:
19
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/js_native_api.h:
20
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/js_native_api_types.h:
21
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/node_api_types.h:
22
22
  /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api/napi-inl.h:
23
23
  /Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api/napi-inl.deprecated.h:
24
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv.h:
25
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/errno.h:
26
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/version.h:
27
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/unix.h:
28
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/threadpool.h:
29
- /Users/runner/Library/Caches/node-gyp/24.13.0/include/node/uv/darwin.h:
24
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv.h:
25
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/errno.h:
26
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/version.h:
27
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/unix.h:
28
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/threadpool.h:
29
+ /Users/runner/Library/Caches/node-gyp/24.14.1/include/node/uv/darwin.h:
Binary file
package/build/config.gypi CHANGED
@@ -1,97 +1,46 @@
1
1
  # Do not edit. File was generated by node-gyp's "configure" step
2
2
  {
3
- "target_defaults": {
4
- "cflags": [],
5
- "configurations": {
6
- "Debug": {
7
- "v8_enable_v8_checks": 0,
8
- "variables": {}
9
- },
10
- "Release": {
11
- "v8_enable_v8_checks": 1,
12
- "variables": {}
13
- }
14
- },
15
- "default_configuration": "Release",
16
- "defines": [],
17
- "include_dirs": [],
18
- "libraries": [],
19
- "msvs_configuration_platform": "ARM64",
20
- "xcode_configuration_platform": "arm64"
21
- },
22
3
  "variables": {
23
- "arm_fpu": "neon",
24
- "asan": 0,
4
+ "use_ccache_win": 0,
25
5
  "clang": 1,
6
+ "llvm_version": "16.0",
7
+ "xcode_version": "16.0",
8
+ "node_prefix": "/",
9
+ "node_install_npm": "true",
10
+ "node_install_corepack": "true",
26
11
  "control_flow_guard": "false",
27
- "coverage": "false",
28
- "dcheck_always_on": 0,
29
- "debug_nghttp2": "false",
12
+ "node_use_amaro": "true",
30
13
  "debug_node": "false",
31
- "enable_lto": "false",
32
- "enable_pgo_generate": "false",
33
- "enable_pgo_use": "false",
34
14
  "error_on_warn": "false",
35
- "force_dynamic_crt": 0,
15
+ "suppress_all_error_on_warn": "false",
16
+ "use_prefix_to_find_headers": "false",
36
17
  "host_arch": "arm64",
37
- "icu_data_in": "../../deps/icu-tmp/icudt77l.dat",
38
- "icu_endianness": "l",
39
- "icu_gyp_path": "tools/icu/icu-generic.gyp",
40
- "icu_path": "deps/icu-small",
41
- "icu_small": "false",
42
- "icu_ver_major": "77",
43
- "libdir": "lib",
44
- "llvm_version": "16.0",
45
- "napi_build_version": "10",
46
- "node_builtin_shareable_builtins": [
47
- "deps/cjs-module-lexer/lexer.js",
48
- "deps/cjs-module-lexer/dist/lexer.js",
49
- "deps/undici/undici.js",
50
- "deps/amaro/dist/index.js"
51
- ],
18
+ "target_arch": "arm64",
52
19
  "node_byteorder": "little",
53
- "node_cctest_sources": [
54
- "src/node_snapshot_stub.cc",
55
- "test/cctest/inspector/test_network_requests_buffer.cc",
56
- "test/cctest/inspector/test_node_protocol.cc",
57
- "test/cctest/node_test_fixture.cc",
58
- "test/cctest/test_aliased_buffer.cc",
59
- "test/cctest/test_base64.cc",
60
- "test/cctest/test_base_object_ptr.cc",
61
- "test/cctest/test_cppgc.cc",
62
- "test/cctest/test_crypto_clienthello.cc",
63
- "test/cctest/test_dataqueue.cc",
64
- "test/cctest/test_environment.cc",
65
- "test/cctest/test_inspector_socket.cc",
66
- "test/cctest/test_inspector_socket_server.cc",
67
- "test/cctest/test_json_utils.cc",
68
- "test/cctest/test_linked_binding.cc",
69
- "test/cctest/test_lru_cache.cc",
70
- "test/cctest/test_node_api.cc",
71
- "test/cctest/test_node_crypto.cc",
72
- "test/cctest/test_node_crypto_env.cc",
73
- "test/cctest/test_node_postmortem_metadata.cc",
74
- "test/cctest/test_node_task_runner.cc",
75
- "test/cctest/test_path.cc",
76
- "test/cctest/test_per_process.cc",
77
- "test/cctest/test_platform.cc",
78
- "test/cctest/test_quic_cid.cc",
79
- "test/cctest/test_quic_error.cc",
80
- "test/cctest/test_quic_tokens.cc",
81
- "test/cctest/test_report.cc",
82
- "test/cctest/test_sockaddr.cc",
83
- "test/cctest/test_string_bytes.cc",
84
- "test/cctest/test_traced_value.cc",
85
- "test/cctest/test_util.cc",
86
- "test/cctest/node_test_fixture.h"
87
- ],
88
- "node_debug_lib": "false",
89
- "node_enable_d8": "false",
20
+ "want_separate_host_toolset": 0,
21
+ "arm_fpu": "neon",
22
+ "node_use_node_snapshot": "true",
23
+ "node_use_node_code_cache": "true",
24
+ "node_write_snapshot_as_array_literals": "false",
90
25
  "node_enable_v8_vtunejit": "false",
91
- "node_enable_v8windbg": "false",
92
- "node_fipsinstall": "false",
93
- "node_install_corepack": "true",
94
- "node_install_npm": "true",
26
+ "enable_pgo_generate": "false",
27
+ "enable_pgo_use": "false",
28
+ "enable_lto": "false",
29
+ "single_executable_application": "true",
30
+ "node_with_ltcg": "false",
31
+ "node_tag": "",
32
+ "node_release_urlbase": "https://nodejs.org/download/release/",
33
+ "node_debug_lib": "false",
34
+ "debug_nghttp2": "false",
35
+ "node_no_browser_globals": "false",
36
+ "node_shared": "false",
37
+ "libdir": "lib",
38
+ "node_module_version": 137,
39
+ "shlib_suffix": "137.dylib",
40
+ "asan": 0,
41
+ "ubsan": 0,
42
+ "coverage": "false",
43
+ "node_target_type": "executable",
95
44
  "node_library_files": [
96
45
  "lib/_http_agent.js",
97
46
  "lib/_http_client.js",
@@ -198,6 +147,8 @@
198
147
  "lib/internal/dns/promises.js",
199
148
  "lib/internal/dns/utils.js",
200
149
  "lib/internal/encoding.js",
150
+ "lib/internal/encoding/single-byte.js",
151
+ "lib/internal/encoding/util.js",
201
152
  "lib/internal/error_serdes.js",
202
153
  "lib/internal/errors.js",
203
154
  "lib/internal/errors/error_source.js",
@@ -313,6 +264,7 @@
313
264
  "lib/internal/readline/utils.js",
314
265
  "lib/internal/repl.js",
315
266
  "lib/internal/repl/await.js",
267
+ "lib/internal/repl/completion.js",
316
268
  "lib/internal/repl/history.js",
317
269
  "lib/internal/repl/utils.js",
318
270
  "lib/internal/socket_list.js",
@@ -363,7 +315,9 @@
363
315
  "lib/internal/test_runner/tests_stream.js",
364
316
  "lib/internal/test_runner/utils.js",
365
317
  "lib/internal/timers.js",
318
+ "lib/internal/tls/common.js",
366
319
  "lib/internal/tls/secure-context.js",
320
+ "lib/internal/tls/wrap.js",
367
321
  "lib/internal/trace_events_async_hooks.js",
368
322
  "lib/internal/tty.js",
369
323
  "lib/internal/url.js",
@@ -441,83 +395,136 @@
441
395
  "lib/worker_threads.js",
442
396
  "lib/zlib.js"
443
397
  ],
444
- "node_module_version": 137,
445
- "node_no_browser_globals": "false",
446
- "node_prefix": "/",
447
- "node_quic": "false",
448
- "node_release_urlbase": "https://nodejs.org/download/release/",
449
- "node_shared": "false",
398
+ "node_cctest_sources": [
399
+ "src/node_snapshot_stub.cc",
400
+ "test/cctest/inspector/test_network_requests_buffer.cc",
401
+ "test/cctest/inspector/test_node_protocol.cc",
402
+ "test/cctest/node_test_fixture.cc",
403
+ "test/cctest/test_aliased_buffer.cc",
404
+ "test/cctest/test_base64.cc",
405
+ "test/cctest/test_base_object_ptr.cc",
406
+ "test/cctest/test_cppgc.cc",
407
+ "test/cctest/test_crypto_clienthello.cc",
408
+ "test/cctest/test_dataqueue.cc",
409
+ "test/cctest/test_environment.cc",
410
+ "test/cctest/test_inspector_socket.cc",
411
+ "test/cctest/test_inspector_socket_server.cc",
412
+ "test/cctest/test_json_utils.cc",
413
+ "test/cctest/test_linked_binding.cc",
414
+ "test/cctest/test_lru_cache.cc",
415
+ "test/cctest/test_node_api.cc",
416
+ "test/cctest/test_node_crypto.cc",
417
+ "test/cctest/test_node_crypto_env.cc",
418
+ "test/cctest/test_node_postmortem_metadata.cc",
419
+ "test/cctest/test_node_task_runner.cc",
420
+ "test/cctest/test_path.cc",
421
+ "test/cctest/test_per_process.cc",
422
+ "test/cctest/test_platform.cc",
423
+ "test/cctest/test_quic_cid.cc",
424
+ "test/cctest/test_quic_error.cc",
425
+ "test/cctest/test_quic_tokens.cc",
426
+ "test/cctest/test_report.cc",
427
+ "test/cctest/test_sockaddr.cc",
428
+ "test/cctest/test_string_bytes.cc",
429
+ "test/cctest/test_traced_value.cc",
430
+ "test/cctest/test_util.cc",
431
+ "test/cctest/node_test_fixture.h"
432
+ ],
433
+ "napi_build_version": "10",
434
+ "node_shared_zlib": "false",
435
+ "node_shared_http_parser": "false",
436
+ "node_shared_libuv": "false",
450
437
  "node_shared_ada": "false",
438
+ "node_shared_simdjson": "false",
439
+ "node_shared_simdutf": "false",
451
440
  "node_shared_brotli": "false",
452
441
  "node_shared_cares": "false",
453
- "node_shared_http_parser": "false",
454
- "node_shared_libuv": "false",
442
+ "node_shared_gtest": "false",
443
+ "node_shared_hdr_histogram": "false",
444
+ "node_shared_merve": "false",
445
+ "node_shared_nbytes": "false",
455
446
  "node_shared_nghttp2": "false",
456
447
  "node_shared_nghttp3": "false",
457
448
  "node_shared_ngtcp2": "false",
458
- "node_shared_openssl": "false",
459
- "node_shared_simdjson": "false",
460
- "node_shared_simdutf": "false",
449
+ "node_use_sqlite": "true",
461
450
  "node_shared_sqlite": "false",
462
451
  "node_shared_uvwasi": "false",
463
- "node_shared_zlib": "false",
464
452
  "node_shared_zstd": "false",
465
- "node_tag": "",
466
- "node_target_type": "executable",
467
- "node_use_amaro": "true",
468
- "node_use_bundled_v8": "true",
469
- "node_use_node_code_cache": "true",
470
- "node_use_node_snapshot": "true",
471
- "node_use_openssl": "true",
472
- "node_use_sqlite": "true",
473
- "node_use_v8_platform": "true",
474
- "node_with_ltcg": "false",
475
- "node_without_node_options": "false",
476
- "node_write_snapshot_as_array_literals": "false",
477
- "openssl_is_fips": "false",
478
- "openssl_quic": "false",
479
- "ossfuzz": "false",
480
- "shlib_suffix": "137.dylib",
481
- "single_executable_application": "true",
482
- "suppress_all_error_on_warn": "false",
483
- "target_arch": "arm64",
484
- "ubsan": 0,
485
- "use_ccache_win": 0,
486
- "use_prefix_to_find_headers": "false",
487
- "v8_enable_31bit_smis_on_64bit_arch": 0,
488
- "v8_enable_extensible_ro_snapshot": 0,
489
- "v8_enable_external_code_space": 0,
490
- "v8_enable_gdbjit": 0,
491
- "v8_enable_hugepage": 0,
492
- "v8_enable_i18n_support": 1,
493
- "v8_enable_inspector": 1,
453
+ "v8_enable_webassembly": 1,
494
454
  "v8_enable_javascript_promise_hooks": 1,
495
455
  "v8_enable_lite_mode": 0,
496
- "v8_enable_maglev": 1,
456
+ "v8_enable_gdbjit": 0,
457
+ "v8_optimized_debug": 1,
458
+ "dcheck_always_on": 0,
497
459
  "v8_enable_object_print": 1,
460
+ "v8_random_seed": 0,
461
+ "v8_promise_internal_field_count": 1,
462
+ "v8_use_siphash": 1,
463
+ "v8_enable_maglev": 1,
498
464
  "v8_enable_pointer_compression": 0,
499
- "v8_enable_pointer_compression_shared_cage": 0,
500
465
  "v8_enable_sandbox": 0,
501
- "v8_enable_webassembly": 1,
502
- "v8_optimized_debug": 1,
503
- "v8_promise_internal_field_count": 1,
504
- "v8_random_seed": 0,
466
+ "v8_enable_pointer_compression_shared_cage": 0,
467
+ "v8_enable_external_code_space": 0,
468
+ "v8_enable_31bit_smis_on_64bit_arch": 0,
469
+ "v8_enable_extensible_ro_snapshot": 0,
505
470
  "v8_trace_maps": 0,
506
- "v8_use_siphash": 1,
507
- "want_separate_host_toolset": 0,
508
- "xcode_version": "16.0",
509
- "nodedir": "/Users/runner/Library/Caches/node-gyp/24.13.0",
471
+ "node_use_v8_platform": "true",
472
+ "node_use_bundled_v8": "true",
473
+ "force_dynamic_crt": 0,
474
+ "node_enable_d8": "false",
475
+ "node_enable_v8windbg": "false",
476
+ "v8_enable_hugepage": 0,
477
+ "node_use_openssl": "true",
478
+ "node_shared_openssl": "false",
479
+ "openssl_is_fips": "false",
480
+ "node_quic": "false",
481
+ "node_fipsinstall": "false",
482
+ "node_without_node_options": "false",
483
+ "openssl_quic": "false",
484
+ "icu_small": "false",
485
+ "v8_enable_i18n_support": 1,
486
+ "icu_gyp_path": "tools/icu/icu-generic.gyp",
487
+ "icu_path": "deps/icu-small",
488
+ "icu_ver_major": "78",
489
+ "icu_endianness": "l",
490
+ "icu_data_in": "../../deps/icu-tmp/icudt78l.dat",
491
+ "v8_enable_inspector": 1,
492
+ "node_builtin_shareable_builtins": [
493
+ "deps/undici/undici.js",
494
+ "deps/amaro/dist/index.js"
495
+ ],
496
+ "ossfuzz": "false",
497
+ "nodedir": "/Users/runner/Library/Caches/node-gyp/24.14.1",
510
498
  "python": "/opt/homebrew/opt/python@3.14/bin/python3.14",
511
499
  "standalone_static_library": 1,
512
- "prefix": "/Users/runner/hostedtoolcache/node/24.13.0/arm64",
513
- "user_agent": "npm/11.6.2 node/v24.13.0 darwin arm64 workspaces/false ci/github-actions",
500
+ "prefix": "/Users/runner/hostedtoolcache/node/24.14.1/arm64",
501
+ "user_agent": "npm/11.11.0 node/v24.14.1 darwin arm64 workspaces/false ci/github-actions",
514
502
  "cache": "/Users/runner/.npm",
515
503
  "node_gyp": "/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
516
- "npm_version": "11.6.2",
517
- "userconfig": "/private/var/folders/kg/7q73ww8s3llgyl61c9z_j5g40000gn/T/20fc2ec49668cc95ea8864d1e9df4ffe/.npmrc",
504
+ "npm_version": "11.11.0",
505
+ "userconfig": "/private/var/folders/tb/y368xp_x10s3ty1b_mtl5mxr0000gn/T/d5aab3f73716915039a0303184de39d0/.npmrc",
518
506
  "init_module": "/Users/runner/.npm-init.js",
519
- "globalconfig": "/Users/runner/hostedtoolcache/node/24.13.0/arm64/etc/npmrc",
507
+ "globalconfig": "/Users/runner/hostedtoolcache/node/24.14.1/arm64/etc/npmrc",
520
508
  "local_prefix": "/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap",
521
- "global_prefix": "/Users/runner/hostedtoolcache/node/24.13.0/arm64"
509
+ "global_prefix": "/Users/runner/hostedtoolcache/node/24.14.1/arm64"
510
+ },
511
+ "target_defaults": {
512
+ "include_dirs": [],
513
+ "libraries": [],
514
+ "defines": [],
515
+ "cflags": [],
516
+ "default_configuration": "Release",
517
+ "configurations": {
518
+ "Release": {
519
+ "variables": {},
520
+ "v8_enable_v8_checks": 1
521
+ },
522
+ "Debug": {
523
+ "variables": {},
524
+ "v8_enable_v8_checks": 0
525
+ }
526
+ },
527
+ "msvs_configuration_platform": "ARM64",
528
+ "xcode_configuration_platform": "arm64"
522
529
  }
523
530
  }
@@ -46,13 +46,13 @@ CFLAGS_OBJC_Debug :=
46
46
  CFLAGS_OBJCC_Debug :=
47
47
 
48
48
  INCS_Debug := \
49
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node \
50
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/src \
51
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/config \
52
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/openssl/include \
53
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/uv/include \
54
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/zlib \
55
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/v8/include
49
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node \
50
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/src \
51
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/config \
52
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/openssl/include \
53
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/uv/include \
54
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/zlib \
55
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/v8/include
56
56
 
57
57
  DEFS_Release := \
58
58
  '-DNODE_GYP_MODULE_NAME=nothing' \
@@ -96,13 +96,13 @@ CFLAGS_OBJC_Release :=
96
96
  CFLAGS_OBJCC_Release :=
97
97
 
98
98
  INCS_Release := \
99
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node \
100
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/src \
101
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/config \
102
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/openssl/include \
103
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/uv/include \
104
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/zlib \
105
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/v8/include
99
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node \
100
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/src \
101
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/config \
102
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/openssl/include \
103
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/uv/include \
104
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/zlib \
105
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/v8/include
106
106
 
107
107
  OBJS := \
108
108
  $(obj).target/$(TARGET)/node_modules/node-addon-api/nothing.o
@@ -55,13 +55,13 @@ CFLAGS_OBJC_Debug :=
55
55
  CFLAGS_OBJCC_Debug :=
56
56
 
57
57
  INCS_Debug := \
58
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node \
59
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/src \
60
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/config \
61
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/openssl/include \
62
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/uv/include \
63
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/zlib \
64
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/v8/include \
58
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node \
59
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/src \
60
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/config \
61
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/openssl/include \
62
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/uv/include \
63
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/zlib \
64
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/v8/include \
65
65
  -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api
66
66
 
67
67
  DEFS_Release := \
@@ -115,13 +115,13 @@ CFLAGS_OBJC_Release :=
115
115
  CFLAGS_OBJCC_Release :=
116
116
 
117
117
  INCS_Release := \
118
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/include/node \
119
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/src \
120
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/config \
121
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/openssl/openssl/include \
122
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/uv/include \
123
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/zlib \
124
- -I/Users/runner/Library/Caches/node-gyp/24.13.0/deps/v8/include \
118
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/include/node \
119
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/src \
120
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/config \
121
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/openssl/openssl/include \
122
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/uv/include \
123
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/zlib \
124
+ -I/Users/runner/Library/Caches/node-gyp/24.14.1/deps/v8/include \
125
125
  -I/Users/runner/work/appium-ios-tuntap/appium-ios-tuntap/node_modules/node-addon-api
126
126
 
127
127
  OBJS := \
package/lib/TunTap.d.ts CHANGED
@@ -15,7 +15,7 @@ export declare class TunTap {
15
15
  private device;
16
16
  private isOpen;
17
17
  private isClosed;
18
- private cleanupHandlers;
18
+ private removeExitListener;
19
19
  constructor(name?: string);
20
20
  open(): boolean;
21
21
  close(): boolean;
package/lib/TunTap.js CHANGED
@@ -1,10 +1,35 @@
1
1
  import { createRequire } from 'node:module';
2
- import { exec } from 'node:child_process';
2
+ import { execFile } from 'node:child_process';
3
+ import { isIPv6 } from 'node:net';
3
4
  import { promisify } from 'node:util';
4
5
  import { log } from './logger.js';
5
6
  const require = createRequire(import.meta.url);
6
7
  const nativeTuntap = require('../build/Release/tuntap.node');
7
- const execPromise = promisify(exec);
8
+ const execFileAsync = promisify(execFile);
9
+ /**
10
+ * Validates that a string is a safe IPv6 route destination (address or prefix).
11
+ * Rejects shell metacharacters to prevent injection even though execFile is safe.
12
+ */
13
+ function isValidIPv6Route(destination) {
14
+ if (!destination || typeof destination !== 'string') {
15
+ return false;
16
+ }
17
+ const parts = destination.split('/');
18
+ if (parts.length > 2) {
19
+ return false;
20
+ }
21
+ const [addr, prefixLen] = parts;
22
+ if (!isIPv6(addr)) {
23
+ return false;
24
+ }
25
+ if (prefixLen !== undefined) {
26
+ const len = Number(prefixLen);
27
+ if (!Number.isInteger(len) || len < 0 || len > 128) {
28
+ return false;
29
+ }
30
+ }
31
+ return true;
32
+ }
8
33
  // Custom error types
9
34
  export class TunTapError extends Error {
10
35
  code;
@@ -33,7 +58,7 @@ export class TunTap {
33
58
  device;
34
59
  isOpen;
35
60
  isClosed;
36
- cleanupHandlers = [];
61
+ removeExitListener = null;
37
62
  constructor(name = '') {
38
63
  this.device = new nativeTuntap.TunDevice(name);
39
64
  this.isOpen = false;
@@ -50,13 +75,9 @@ export class TunTap {
50
75
  }
51
76
  };
52
77
  process.once('exit', cleanup);
53
- process.once('SIGINT', cleanup);
54
- process.once('SIGTERM', cleanup);
55
- this.cleanupHandlers.push(() => {
78
+ this.removeExitListener = () => {
56
79
  process.removeListener('exit', cleanup);
57
- process.removeListener('SIGINT', cleanup);
58
- process.removeListener('SIGTERM', cleanup);
59
- });
80
+ };
60
81
  }
61
82
  open() {
62
83
  if (this.isClosed) {
@@ -83,6 +104,10 @@ export class TunTap {
83
104
  return this.isOpen;
84
105
  }
85
106
  close() {
107
+ if (this.removeExitListener) {
108
+ this.removeExitListener();
109
+ this.removeExitListener = null;
110
+ }
86
111
  if (!this.isClosed) {
87
112
  try {
88
113
  if (this.isOpen) {
@@ -90,9 +115,6 @@ export class TunTap {
90
115
  this.isOpen = false;
91
116
  }
92
117
  this.isClosed = true;
93
- // Run cleanup handlers
94
- this.cleanupHandlers.forEach((handler) => handler());
95
- this.cleanupHandlers = [];
96
118
  }
97
119
  catch (err) {
98
120
  throw new TunTapError(`Failed to close device: ${err.message}`);
@@ -157,9 +179,7 @@ export class TunTap {
157
179
  if (this.isClosed) {
158
180
  throw new TunTapError('Device has been closed');
159
181
  }
160
- // Validate IPv6 address format
161
- const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
162
- if (!ipv6Regex.test(address)) {
182
+ if (!isIPv6(address)) {
163
183
  throw new TypeError('Invalid IPv6 address format');
164
184
  }
165
185
  // Validate MTU
@@ -169,29 +189,25 @@ export class TunTap {
169
189
  const platform = process.platform;
170
190
  try {
171
191
  if (platform === 'darwin') {
172
- // macOS configuration
173
- await execPromise(`sudo ifconfig ${this.name} inet6 ${address} prefixlen 64 up`);
174
- await execPromise(`sudo ifconfig ${this.name} mtu ${mtu}`);
192
+ await execFileAsync('sudo', ['ifconfig', this.name, 'inet6', address, 'prefixlen', '64', 'up']);
193
+ await execFileAsync('sudo', ['ifconfig', this.name, 'mtu', String(mtu)]);
175
194
  }
176
195
  else if (platform === 'linux') {
177
- // Linux configuration
178
196
  try {
179
- // Check if ip command is available
180
- await execPromise('which ip');
197
+ await execFileAsync('which', ['ip']);
181
198
  }
182
199
  catch {
183
200
  throw new TunTapError('The "ip" command is not available. Please install the iproute2 package (e.g., sudo apt install iproute2)');
184
201
  }
185
202
  try {
186
- await execPromise(`sudo ip -6 addr add ${address}/64 dev ${this.name}`);
187
- await execPromise(`sudo ip link set dev ${this.name} up mtu ${mtu}`);
203
+ await execFileAsync('sudo', ['ip', '-6', 'addr', 'add', `${address}/64`, 'dev', this.name]);
204
+ await execFileAsync('sudo', ['ip', 'link', 'set', 'dev', this.name, 'up', 'mtu', String(mtu)]);
188
205
  }
189
206
  catch (err) {
190
207
  if (err.message.includes('Permission denied')) {
191
208
  throw new TunTapPermissionError(`Permission denied when configuring network interface. Make sure you have sudo privileges or run the application with sudo.`);
192
209
  }
193
210
  else if (err.message.includes('File exists')) {
194
- // Address already configured, which might be okay
195
211
  log.warn(`Address ${address} may already be configured on ${this.name}`);
196
212
  }
197
213
  else {
@@ -217,27 +233,23 @@ export class TunTap {
217
233
  if (this.isClosed) {
218
234
  throw new TunTapError('Device has been closed');
219
235
  }
220
- // Basic validation of destination format
221
- if (!destination || typeof destination !== 'string') {
222
- throw new TypeError('Destination must be a non-empty string');
236
+ if (!isValidIPv6Route(destination)) {
237
+ throw new TypeError('Destination must be a valid IPv6 address or prefix (e.g. fd00::1/64)');
223
238
  }
224
239
  const platform = process.platform;
225
240
  try {
226
241
  if (platform === 'darwin') {
227
- // macOS route
228
- await execPromise(`sudo route -n add -inet6 ${destination} -interface ${this.name}`);
242
+ await execFileAsync('sudo', ['route', '-n', 'add', '-inet6', destination, '-interface', this.name]);
229
243
  }
230
244
  else if (platform === 'linux') {
231
- // Linux route
232
245
  try {
233
- await execPromise(`sudo ip -6 route add ${destination} dev ${this.name}`);
246
+ await execFileAsync('sudo', ['ip', '-6', 'route', 'add', destination, 'dev', this.name]);
234
247
  }
235
248
  catch (err) {
236
249
  if (err.message.includes('Permission denied')) {
237
250
  throw new TunTapPermissionError(`Permission denied when adding route. Make sure you have sudo privileges or run the application with sudo.`);
238
251
  }
239
252
  else if (err.message.includes('File exists')) {
240
- // Route already exists, which is fine
241
253
  log.info(`Route to ${destination} already exists`);
242
254
  }
243
255
  else {
@@ -250,7 +262,6 @@ export class TunTap {
250
262
  }
251
263
  }
252
264
  catch (err) {
253
- // Only throw if it's not the "route already exists" case we handled above
254
265
  if (err instanceof TunTapError) {
255
266
  throw err;
256
267
  }
@@ -263,22 +274,22 @@ export class TunTap {
263
274
  if (!this.isOpen) {
264
275
  throw new TunTapError('Device not open');
265
276
  }
277
+ if (!isValidIPv6Route(destination)) {
278
+ throw new TypeError('Destination must be a valid IPv6 address or prefix (e.g. fd00::1/64)');
279
+ }
266
280
  const platform = process.platform;
267
281
  try {
268
282
  if (platform === 'darwin') {
269
- // macOS route removal
270
- await execPromise(`sudo route -n delete -inet6 ${destination}`);
283
+ await execFileAsync('sudo', ['route', '-n', 'delete', '-inet6', destination]);
271
284
  }
272
285
  else if (platform === 'linux') {
273
- // Linux route removal
274
- await execPromise(`sudo ip -6 route del ${destination} dev ${this.name}`);
286
+ await execFileAsync('sudo', ['ip', '-6', 'route', 'del', destination, 'dev', this.name]);
275
287
  }
276
288
  else {
277
289
  throw new TunTapError(`Unsupported platform: ${platform}`);
278
290
  }
279
291
  }
280
292
  catch (err) {
281
- // Ignore errors if route doesn't exist
282
293
  if (!err.message.includes('not in table') && !err.message.includes('No such process')) {
283
294
  throw new TunTapError(`Failed to remove route: ${err.message}`);
284
295
  }
@@ -294,8 +305,7 @@ export class TunTap {
294
305
  const platform = process.platform;
295
306
  try {
296
307
  if (platform === 'darwin') {
297
- const { stdout } = await execPromise(`netstat -I ${this.name} -b`);
298
- // Parse macOS netstat output
308
+ const { stdout } = await execFileAsync('netstat', ['-I', this.name, '-b']);
299
309
  const lines = stdout.trim().split('\n');
300
310
  if (lines.length < 2) {
301
311
  throw new Error('Unexpected netstat output');
@@ -307,14 +317,12 @@ export class TunTap {
307
317
  rxBytes: parseInt(stats[6], 10) || 0,
308
318
  txPackets: parseInt(stats[7], 10) || 0,
309
319
  txErrors: parseInt(stats[8], 10) || 0,
310
- txBytes: parseInt(stats[9], 10) || 0
320
+ txBytes: parseInt(stats[9], 10) || 0,
311
321
  };
312
322
  }
313
323
  else if (platform === 'linux') {
314
- const { stdout } = await execPromise(`ip -s link show ${this.name}`);
315
- // Parse Linux ip command output
324
+ const { stdout } = await execFileAsync('ip', ['-s', 'link', 'show', this.name]);
316
325
  const lines = stdout.trim().split('\n');
317
- // Find RX and TX statistics
318
326
  let rxIndex = -1;
319
327
  let txIndex = -1;
320
328
  for (let i = 0; i < lines.length; i++) {
@@ -336,7 +344,7 @@ export class TunTap {
336
344
  rxErrors: parseInt(rxStats[2], 10) || 0,
337
345
  txBytes: parseInt(txStats[0], 10) || 0,
338
346
  txPackets: parseInt(txStats[1], 10) || 0,
339
- txErrors: parseInt(txStats[2], 10) || 0
347
+ txErrors: parseInt(txStats[2], 10) || 0,
340
348
  };
341
349
  }
342
350
  else {
package/lib/tunnel.js CHANGED
@@ -2,44 +2,6 @@ import { log } from './logger.js';
2
2
  import { TunTap } from './TunTap.js';
3
3
  import { EventEmitter } from 'node:events';
4
4
  import { Buffer } from 'node:buffer';
5
- // Global registry for active tunnel managers
6
- const activeTunnelManagers = new Set();
7
- // Setup process signal handlers
8
- let signalHandlersSetup = false;
9
- function setupSignalHandlers() {
10
- if (signalHandlersSetup) {
11
- return;
12
- }
13
- signalHandlersSetup = true;
14
- const gracefulShutdown = async (signal) => {
15
- log.debug(`Received ${signal}, initiating graceful shutdown...`);
16
- // Copy the set to avoid modification during iteration
17
- const managers = Array.from(activeTunnelManagers);
18
- // Stop all tunnel managers
19
- await Promise.all(managers.map((manager) => {
20
- try {
21
- return manager.stop();
22
- }
23
- catch (err) {
24
- log.error('Error stopping tunnel manager:', err);
25
- }
26
- }));
27
- log.debug('All tunnel managers stopped, exiting...');
28
- process.exit(0);
29
- };
30
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
31
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
32
- // Handle uncaught exceptions
33
- process.on('uncaughtException', async (err) => {
34
- log.error('Uncaught exception:', err);
35
- await gracefulShutdown('uncaughtException');
36
- process.exit(1);
37
- });
38
- // Handle unhandled promise rejections
39
- process.on('unhandledRejection', (reason, promise) => {
40
- log.error(`Unhandled rejection at: ${promise} reason: ${reason}`);
41
- });
42
- }
43
5
  export class TunnelManager extends EventEmitter {
44
6
  tun;
45
7
  cancelled;
@@ -59,10 +21,6 @@ export class TunnelManager extends EventEmitter {
59
21
  this.packetQueue = [];
60
22
  this.deviceConn = null;
61
23
  this.cleanupPromise = null;
62
- // Setup signal handlers on first tunnel manager creation
63
- setupSignalHandlers();
64
- // Register this manager
65
- activeTunnelManagers.add(this);
66
24
  }
67
25
  addPacketConsumer(consumer) {
68
26
  this.packetConsumers.add(consumer);
@@ -364,8 +322,6 @@ export class TunnelManager extends EventEmitter {
364
322
  }
365
323
  this.tun = null;
366
324
  }
367
- // Unregister from active managers
368
- activeTunnelManagers.delete(this);
369
325
  log.debug(`Tunnel for ${tunName} closed successfully`);
370
326
  }
371
327
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-ios-tuntap",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Native TUN/TAP interface module for Node.js",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",