termux-packages icon indicating copy to clipboard operation
termux-packages copied to clipboard

[Bug]: Nodejs uv_interface_addresses returned Unknown system error 13

Open neophob opened this issue 2 years ago • 22 comments

Problem description

When I use the Termux app, install Node.js (latest and lts) and run Node.js - the call to os.networkInterfaces() works.

However when I build Node.js myself using the Termux Docker images (./build-package.sh openssl nodejs), each call to os.networkInterfaces() fails with A system error occurred: uv_interface_addresses returned Unknown system error 13 (Unknown system error 13) on my Android 11 system. (Permission denied).

it looks like this is because Android 11 forbids apps to query MAC addresses. Links:

  • Analyse https://gitlab.com/staltz/manyverse/-/issues/1411
  • a potential fix here https://github.com/JaneaSystems/nodejs-mobile/commit/73d5d375dbd672c3df8556a83ad122a078d21ed2

What steps will reproduce the bug?

start self compiled nodejs binary on your Android 11 phone, enter os.networkInterfaces() in the repl.

Tested with the latest nodejs and nodejs-lts version

What is the expected behavior?

call does not fail

System information

termux-info:


neophob avatar May 31 '22 21:05 neophob

Did you build in the docker image, or by git cloning termux-packages and running ./build-package.sh on device?

Building in the docker image should give an identical nodejs{-lts} package as the one in our repos, unless you've made changes to the build recipe?

Grimler91 avatar Jun 01 '22 07:06 Grimler91

I did git cloning termux-packages and running ./build-package.sh - but not on the device but on my macbook.

And no changes to the nodejs packages - i basically followed https://github.com/termux/termux-packages/wiki/Build-environment and https://github.com/termux/termux-packages/wiki/Building-packages

more background information: I want to run a nodejs app on Android and use https://github.com/siepra/node-on-android-demo as starting point.

neophob avatar Jun 01 '22 08:06 neophob

Note: I did NOT build the node package on my Android device, but on my Macbook in a Docker container. I the installed the node binary on my Android device. So I think the "on-device packaging" tag is wrong.

neophob avatar Jun 02 '22 09:06 neophob

More info:

  • the Android Termux App has targetSDK 28, that's why the os.networkInterfaces() call works
  • if the Termux App targets SDK 30, the os.networkInterfaces() call will fail with the error described

neophob avatar Jun 02 '22 09:06 neophob

@neophob Can you try building Node.js with the following additional patch:-

--- ./deps/uv/src/unix/linux-core.c.orig	2022-06-03 12:37:01.127102137 +0530
+++ ./deps/uv/src/unix/linux-core.c	2022-06-03 12:37:11.887102132 +0530
@@ -43,14 +43,6 @@
 #include <fcntl.h>
 #include <time.h>
 
-#define HAVE_IFADDRS_H 1
-
-#ifdef __UCLIBC__
-# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
-#  undef HAVE_IFADDRS_H
-# endif
-#endif
-
 #ifdef HAVE_IFADDRS_H
 # if defined(__ANDROID__)
 #  include "uv/android-ifaddrs.h"

This will make sure that uv_inteface_addresses() will return UV_ENOSYS which makes much more sense then failing as above.

Also would like to know what's your use case of os.networkInterfaces().

thunder-coding avatar Jun 03 '22 07:06 thunder-coding

Thanks @thunder-coding ! I applied the patch building nodejs:

...
Applying patch: deps-uv-src-unix-core.c.patch
Applying patch: deps-uv-src-unix-net.c.patch       << thats the patch above
Applying patch: deps-uv-src-unix-process.c.patch
Applying patch: deps-uv-uv.gyp.patch
Applying patch: deps-v8-src-flags-flag-definitions.h.patch
Applying patch: deps-v8-src-logging-log.cc.patch
Applying patch: deps-v8-src-trap-handler-trap-handler.h.patch
...

but then the build fails:

  aarch64-linux-android-clang -o /home/builder/.termux-build/nodejs/src/out/Release/obj.target/libuv/deps/uv/src/unix/pthread-fixes.o ../deps/uv/src/unix/pthread-fixes.c '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D__STDC_FORMAT_MACROS' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D_GLIBCXX_USE_C99_MATH' -I../deps/uv/include -I../deps/uv/src -I/data/data/com.termux/files/usr/include  -Wall -Wextra -Wno-unused-parameter -fvisibility=hidden -g --std=gnu89 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes -fno-strict-aliasing -O3 -fno-omit-frame-pointer -fPIC  -MMD -MF /home/builder/.termux-build/nodejs/src/out/Release/.deps//home/builder/.termux-build/nodejs/src/out/Release/obj.target/libuv/deps/uv/src/unix/pthread-fixes.o.d.raw  -I/data/data/com.termux/files/usr/include  -fstack-protector-strong -Oz -c
../deps/uv/src/unix/linux-core.c:636:38: warning: declaration of 'struct ifaddrs' will not be visible outside of this function [-Wvisibility]
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
                                     ^
../deps/uv/src/unix/linux-core.c:637:13: error: incomplete definition of type 'struct ifaddrs'
  if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
         ~~~^
../deps/uv/src/unix/linux-core.c:636:38: note: forward declaration of 'struct ifaddrs'
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
                                     ^
../deps/uv/src/unix/linux-core.c:637:42: error: incomplete definition of type 'struct ifaddrs'
  if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
                                      ~~~^
../deps/uv/src/unix/linux-core.c:636:38: note: forward declaration of 'struct ifaddrs'
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
                                     ^
../deps/uv/src/unix/linux-core.c:639:10: error: incomplete definition of type 'struct ifaddrs'
  if (ent->ifa_addr == NULL)
      ~~~^
../deps/uv/src/unix/linux-core.c:636:38: note: forward declaration of 'struct ifaddrs'
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
                                     ^
../deps/uv/src/unix/linux-core.c:645:10: error: incomplete definition of type 'struct ifaddrs'
  if (ent->ifa_addr->sa_family == PF_PACKET)
      ~~~^
../deps/uv/src/unix/linux-core.c:636:38: note: forward declaration of 'struct ifaddrs'
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
                                     ^
1 warning and 4 errors generated.
make[1]: *** [deps/uv/libuv.target.mk:141: /home/builder/.termux-build/nodejs/src/out/Release/obj.target/libuv/deps/uv/src/unix/linux-core.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:113: node] Error 2

Also would like to know what's your use case of os.networkInterfaces().

My use case is reuse a nodejs application in a mobile app. the os.networkInterfaces() call if not used directly - BUT there are some parts the use that code. the problem today is the error case which could lead to weird situations

neophob avatar Jun 03 '22 08:06 neophob

@neophob The following updated patch should work:-

--- ./deps/uv/src/unix/linux-core.c.orig	2022-06-03 12:37:01.127102137 +0530
+++ ./deps/uv/src/unix/linux-core.c	2022-06-03 14:36:13.308341930 +0530
@@ -43,14 +43,6 @@
 #include <fcntl.h>
 #include <time.h>
 
-#define HAVE_IFADDRS_H 1
-
-#ifdef __UCLIBC__
-# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
-#  undef HAVE_IFADDRS_H
-# endif
-#endif
-
 #ifdef HAVE_IFADDRS_H
 # if defined(__ANDROID__)
 #  include "uv/android-ifaddrs.h"
@@ -640,7 +632,7 @@
   return val;
 }
 
-
+#ifdef HAVE_IFADDRS_H
 static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
     return 1;
@@ -654,6 +646,7 @@
     return exclude_type;
   return !exclude_type;
 }
+#endif
 
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 #ifndef HAVE_IFADDRS_H

And yeah, it's an upstream bug that uv__ifaddr_exclude is compiled even when HAVE_IFADDRS_H is not defined. The updated patch should fix it!

Also, the bug is fixed in libuv 1.44.1. Link to exact commit: https://github.com/libuv/libuv/commit/c40f8cb9f8ddf69d116952f8924a11ec0623b445. So no need to send it upstream, since they've already fixed it on their end :)

thunder-coding avatar Jun 03 '22 09:06 thunder-coding

Nice, that patch worked.

Now i get a different error: A system error occurred: undefined returned undefined (undefined) with stacktrace:

at Object.networkInterfaces (node:os:264:16)
at userspace js code where os.networkInterfaces() is used

neophob avatar Jun 03 '22 11:06 neophob

Now i get a different error: A system error occurred: undefined returned undefined (undefined) with stacktrace:

Well that's because your code (or most probably one of your dependencies) hasn't been designed to work in situations where uv_network_interfaces might not be implemented. Can you share the full stack trace, so that the culprit dependency (or your package) can be tracked

thunder-coding avatar Jun 03 '22 12:06 thunder-coding

Well that's because your code (or most probably one of your dependencies) hasn't been designed to work in situations where uv_network_interfaces might not be implemented.

Not sure if I fully agree, as Nodejs docs say, that os.networkInterfaces() returns an Object (which includes an empty object) - but a system error should not be thrown there.

Can you share the full stack trace, so that the culprit dependency (or your package) can be tracked

that IS the whole usable stacktrace of the code, my function call looks like return os.networkInterfaces();, that's it. Here's the raw stacktrace:

"SystemError [ERR_SYSTEM_ERROR]: A system error occurred: undefined returned undefined (undefined)
    at Object.networkInterfaces (node:os:264:16)
    at E._getInterfaces (/data/data/app.fqdn/files/nodeapp/index.js:1:260599)
    at E.getLanInterface (/data/data/app.fqdn/files/nodeapp/index.js:1:260702)
    at E.getLanAddressIPv4 (/data/data/app.fqdn/files/nodeapp/index.js:1:260898)
    at E.getLanAddress (/data/data/app.fqdn/files/nodeapp/index.js:1:261111)
    at /data/data/app.fqdn/files/nodeapp/index.js:1:326359
    at Layer.handle [as handle_request] (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/layer.js:95:5)
    at next (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/route.js:144:13)
    at Route.dispatch (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/route.js:114:3)
    at Layer.handle [as handle_request] (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/layer.js:95:5)
    at /data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:284:15
    at Function.process_params (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:346:12)
    at next (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:280:10)
    at Function.handle (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:175:3)
    at router (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as handle_request] (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:328:13)
    at /data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:346:12)
    at next (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:280:10)
    at Function.handle (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:175:3)
    at router (/data/data/app.fqdn/files/nodeapp/node_modules/express/lib/router/index.js:47:12)"

neophob avatar Jun 03 '22 14:06 neophob

is there anything I can do help diagnose this issue? I'm pretty clueless tbh at the moment, any hints are appreciated!

neophob avatar Jun 09 '22 08:06 neophob

is there anything I can do help diagnose this issue? I'm pretty clueless tbh at the moment, any hints are appreciated!

It seems like you're using a bundler to bundle your application. If you can give me access to the source code of your app, I can certainly look into the place where os.networkInterfaces() is called and whether there is a possible workaround for the same. Best regards, Yaksh.

thunder-coding avatar Jun 09 '22 13:06 thunder-coding

Yeah that is from the bundled version. Here's a copy of the code that crash

const os = require('os');

<snip>

SystemInfo.prototype._getInterfaces = function() {
  return os.networkInterfaces();  << here the crash happens
};

SystemInfo.prototype.getLanInterface = function() {
  const res = this._getInterfaces();
  return res[this._ifaceNameLan];
};

as you can see, the code is pretty basic and it crashes when the os.networkInterfaces() is used. The crash happens only if the Android targetSDK is set to 30+, it works when targetSDK is set to 28.

neophob avatar Jun 09 '22 14:06 neophob

Thanks @thunder-coding for your feedback, is my example above enough or is there anything I can do to help you reproducing the problem?

neophob avatar Jun 13 '22 13:06 neophob

Termux targets sdk level 28 for a reason, so I guess we won't be able to reproduce the issue in termux-app (and therefore @thunder-coding asked for access to the code of your app I guess).

IMHO this issue isn't really termux related. Maybe other nodejs developers can help if you open an issue in their repo

Grimler91 avatar Jun 13 '22 14:06 Grimler91

IMHO this issue isn't really termux related. Maybe other nodejs developers can help if you open an issue in their repo

Instead of opening the issue in the nodejs GitHub repo, it'll make more sense to open it in the package's repo which depends on os.networkInterfaces(). Just grep through the node_modules/ directory to find out which package makes use of it.

thunder-coding avatar Jun 14 '22 01:06 thunder-coding

Termux targets sdk level 28 https://github.com/termux/termux-app/issues/2155, so I guess we won't be able to reproduce the issue.

Yeah, I wanted to bring that issue up for the future (and my use case). Maybe it's my fault thinking that the termux packages support also post SDK 28 devices.

Instead of opening the issue in the nodejs GitHub repo, it'll make more sense to open it in the package's repo which depends on os.networkInterfaces().

This does not make sense as os.networkInterfaces() is a NodeJS API call. There is no reason to use something else from a developers point of view.

neophob avatar Jun 14 '22 05:06 neophob

This issue/PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 29 '22 05:07 stale[bot]

I also meet the same problem, after some investigation, it was because the node had some problem, and I change a node for my pod then it solved, just share the info for others who may meet the same problem with me.

node:os:68
      throw new ERR_SYSTEM_ERROR(ctx);
      ^

SystemError [ERR_SYSTEM_ERROR]: A system error occurred: uv_interface_addresses returned Unknown system error 13 (Unknown system error 13)    at Object.networkInterfaces (node:os:259:16)
    at getAllIPAddresses (/layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/newrelic/lib/collector/facts.js:95:25)
    at factMapCb (/layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/newrelic/lib/collector/facts.js:72:27)
    at /layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/async/dist/async.js:3681:19
    at wrapper (/layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/async/dist/async.js:271:20)
    at iterateeCallback (/layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/async/dist/async.js:427:28)
    at /layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/async/dist/async.js:327:20
    at /layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/async/dist/async.js:3679:17
    at onRefreshFinish (/layers/tanzu-buildpacks_new-relic/new-relic-nodejs/node_modules/newrelic/lib/environment.js:609:5)
  code: 'ERR_SYSTEM_ERROR',
  info: {
    errno: 13,
    code: 'Unknown system error 13',
    message: 'Unknown system error 13',
    syscall: 'uv_interface_addresses'
  },
  errno: [Getter/Setter],
  syscall: [Getter/Setter]
}

zhoufenqin avatar Oct 18 '22 07:10 zhoufenqin

Facing the same problem. Is there any workaround / temporary fix for this? uv_interface_addresses is pretty common node API. Almost any dev server relies on it.

noonesimg avatar Jan 04 '23 09:01 noonesimg

@noonesimg The workaround is to use targets sdk level 28 - let me know if you found another solution

neophob avatar Jan 04 '23 10:01 neophob

@neophob thanks! Can you specify plz, do I need to rebuild the whole termux-app with sdk level 28, or is there a way to just rebuild the nodejs package?

noonesimg avatar Jan 05 '23 08:01 noonesimg

For those comming here after trying to use the C++ extension for code-server, I found a workaround:

  1. Format the file with the error with prettier
    1. npm i --global prettier
    2. prettier -w /data/data/com.termux/files/usr/lib/code-server/lib/vscode/out/vs/server/node/server.main.js
  2. Edit /data/data/com.termux/files/usr/lib/code-server/lib/vscode/out/vs/server/node/server.main.js and add befor line 16050 (the line with error, might be another line for you) to:

return '00:00:00:00:00:00';

So the whole function becomes:

function I() {
        return '00:00:00:00:00:00';
        const L = (0, os.networkInterfaces())();
        for (const R in L) { 
        const b = L[R];
                  if (b) {
                    for (const { mac: d } of b) if (a(d)) return d;
                  }
                }
        throw new Error("Unable to retrieve mac address (unexpected format)");
}

I found this out after reading the documentation for os.networkInterfaces() and noticing that this function just returns the first mac address of the first interface in the system. Seems to work for me for now.

VayuDev avatar Nov 04 '23 20:11 VayuDev