[fdio] Initial implementation of getifaddrs
Sets up the API plumbing and implement getifaddrs to the point where a
list of all addresses are returned.
Due to lack of support in the current version of the netstack,
broadcast address (missing IFF_BROADCAST flag) and destination address
are not set. They will be added when corresponding support is added in
the netstack.
Support for AF_PACKET addresses will be added separately.
Test:
fx test -d getifaddrs-netemul-test
fx test --host getifaddrs-test
Bug: 30719, 54162, 54163
Change-Id: I52910b5bbf5a4d493fd9b591e1dbb2203aa51ef9
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/398773
Commit-Queue: Jay Zhuang <jayzhuang@google.com>
Reviewed-by: Tamir Duberstein <tamird@google.com>
Reviewed-by: Adam Barth <abarth@google.com>
Reviewed-by: Chris Tam <godtamit@google.com>
Testability-Review: Tamir Duberstein <tamird@google.com>
API-Review: Adam Barth <abarth@google.com>
diff --git a/sdk/fidl/fuchsia.net.stack/stack.fidl b/sdk/fidl/fuchsia.net.stack/stack.fidl
index 49f179e..13f01fd 100644
--- a/sdk/fidl/fuchsia.net.stack/stack.fidl
+++ b/sdk/fidl/fuchsia.net.stack/stack.fidl
@@ -46,6 +46,7 @@
3: AdministrativeStatus administrative;
};
+// TODO(https://fxbug.dev/54163): use `fuchsia.net.InterfaceAddress` instead.
struct InterfaceAddress {
/// The IP address of the interface.
fuchsia.net.IpAddress ip_address;
diff --git a/sdk/fidl/fuchsia.net/net.fidl b/sdk/fidl/fuchsia.net/net.fidl
index a47f8c7..9e761c1 100644
--- a/sdk/fidl/fuchsia.net/net.fidl
+++ b/sdk/fidl/fuchsia.net/net.fidl
@@ -33,11 +33,11 @@
uint16 port;
};
-/// Subnet describes an IP subnetwork, where all host IP addresses share the same most significant
-/// bits.
+// TODO(https://fxbug.dev/54163): rename Subnet to AddressWithPrefix when
+// binding support is ready, so we don't have to recursively fix all users.
+/// An IP address with its subnet prefix length.
struct Subnet {
- /// The Ipv4 or Ipv6 address. Only the `prefix_len` most significant bits may be set in `addr`;
- /// all bits in the host portion of the address must be zero.
+ /// The Ipv4 or Ipv6 address.
IpAddress addr;
/// The prefix length of the netmask. E.g. for 192.168.1.0/24, the prefix
diff --git a/sdk/fidl/fuchsia.posix.socket/BUILD.gn b/sdk/fidl/fuchsia.posix.socket/BUILD.gn
index 2d10404..e94afa9e 100644
--- a/sdk/fidl/fuchsia.posix.socket/BUILD.gn
+++ b/sdk/fidl/fuchsia.posix.socket/BUILD.gn
@@ -8,5 +8,8 @@
sdk_category = "partner"
api = "fuchsia.posix.socket.api"
sources = [ "socket.fidl" ]
- public_deps = [ "//sdk/fidl/fuchsia.io" ]
+ public_deps = [
+ "//sdk/fidl/fuchsia.io",
+ "//sdk/fidl/fuchsia.net",
+ ]
}
diff --git a/sdk/fidl/fuchsia.posix.socket/fuchsia.posix.socket.api b/sdk/fidl/fuchsia.posix.socket/fuchsia.posix.socket.api
index 7c1cec4..733fdba 100644
--- a/sdk/fidl/fuchsia.posix.socket/fuchsia.posix.socket.api
+++ b/sdk/fidl/fuchsia.posix.socket/fuchsia.posix.socket.api
@@ -1,3 +1,3 @@
{
- "fidl/fuchsia.posix.socket": "43a271948d74960c04d7ff1aeadd087f"
+ "fidl/fuchsia.posix.socket": "a3ac470444e23f55ad16c4d05755c8b1"
}
\ No newline at end of file
diff --git a/sdk/fidl/fuchsia.posix.socket/socket.fidl b/sdk/fidl/fuchsia.posix.socket/socket.fidl
index 9d47b74..159cafb 100644
--- a/sdk/fidl/fuchsia.posix.socket/socket.fidl
+++ b/sdk/fidl/fuchsia.posix.socket/socket.fidl
@@ -5,6 +5,7 @@
library fuchsia.posix.socket;
using fuchsia.io;
+using fuchsia.net;
using zx;
/// Chosen to match `sizeof(struct sockaddr_storage)`.
@@ -87,6 +88,19 @@
Accept(int16 flags) -> (StreamSocket s) error int32;
};
+/// Holds information about an interface and its addresses.
+table InterfaceAddresses {
+ /// ID of the interface.
+ 1: uint64 id;
+ /// Name of the interface.
+ 2: interface_name name;
+ /// Contains the interface flags, as returned by the SIOCGIFFLAGS ioctl
+ /// operation.
+ 3: uint32 flags;
+ /// All addresses currently assigned to the interface.
+ 4: vector<fuchsia.net.Subnet>:MAX addresses;
+};
+
/// Provider implements the POSIX sockets API.
[Discoverable]
protocol Provider {
@@ -99,4 +113,8 @@
/// Looks up an interface by its name and returns its index. Returns `ZX_ERR_NOT_FOUND` if the
/// specified name doesn't exist.
InterfaceNameToIndex(interface_name name) -> (uint64 index) error zx.status;
+
+ /// Requests a list of [`fuchsia.posix.socket.InterfaceAddresses`]
+ /// describing the network interfaces on the system.
+ GetInterfaceAddresses() -> (vector<InterfaceAddresses>:MAX interfaces);
};
diff --git a/sdk/lib/fdio/bsdsocket.cc b/sdk/lib/fdio/bsdsocket.cc
index 2540a82..3e1b3ff 100644
--- a/sdk/lib/fdio/bsdsocket.cc
+++ b/sdk/lib/fdio/bsdsocket.cc
@@ -4,8 +4,10 @@
#include <fcntl.h>
#include <fuchsia/net/llcpp/fidl.h>
+#include <ifaddrs.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/io.h>
+#include <net/if.h>
#include <netdb.h>
#include <poll.h>
#include <sys/socket.h>
@@ -504,3 +506,79 @@
}
return 0;
}
+
+// TODO(https://fxbug.dev/30719): set ifa_ifu.ifu_broadaddr and ifa_ifu.ifu_dstaddr.
+//
+// AF_PACKET addresses containing lower-level details about the interfaces are not included in the
+// result list because raw sockets are not supported on Fuchsia.
+__EXPORT
+int getifaddrs(struct ifaddrs** ifap) {
+ fsocket::Provider::SyncClient* provider = nullptr;
+ zx_status_t status = fdio_get_socket_provider(&provider);
+ if (status != ZX_OK) {
+ return ERROR(status);
+ }
+
+ auto response = provider->GetInterfaceAddresses();
+ status = response.status();
+ if (status != ZX_OK) {
+ return ERROR(status);
+ }
+
+ for (const auto& iface : response.Unwrap()->interfaces) {
+ if (!iface.has_name() || !iface.has_addresses()) {
+ continue;
+ }
+
+ const auto& if_name = iface.name();
+ for (const auto& address : iface.addresses()) {
+ auto ifs = static_cast<struct ifaddrs_storage*>(calloc(1, sizeof(struct ifaddrs_storage)));
+ if (ifs == nullptr) {
+ return -1;
+ }
+ const size_t n = std::min(if_name.size(), sizeof(ifs->name));
+ memcpy(ifs->name, if_name.data(), n);
+ ifs->name[n] = 0;
+ ifs->ifa.ifa_name = ifs->name;
+
+ const auto& addr = address.addr;
+ const uint8_t prefix_len = address.prefix_len;
+
+ switch (addr.which()) {
+ case fnet::IpAddress::Tag::kIpv4: {
+ const auto& addr_bytes = addr.ipv4().addr;
+ copy_addr(&ifs->ifa.ifa_addr, AF_INET, &ifs->addr,
+ const_cast<uint8_t*>(addr_bytes.data()), addr_bytes.size(), iface.id());
+ gen_netmask(&ifs->ifa.ifa_netmask, AF_INET, &ifs->netmask, prefix_len);
+ break;
+ }
+ case fnet::IpAddress::Tag::kIpv6: {
+ const auto& addr_bytes = addr.ipv6().addr;
+ copy_addr(&ifs->ifa.ifa_addr, AF_INET6, &ifs->addr,
+ const_cast<uint8_t*>(addr_bytes.data()), addr_bytes.size(), iface.id());
+ gen_netmask(&ifs->ifa.ifa_netmask, AF_INET6, &ifs->netmask, prefix_len);
+ break;
+ }
+ }
+
+ if (iface.has_flags()) {
+ ifs->ifa.ifa_flags = iface.flags();
+ }
+
+ *ifap = &ifs->ifa;
+ ifap = &ifs->ifa.ifa_next;
+ }
+ }
+
+ return 0;
+}
+
+__EXPORT
+void freeifaddrs(struct ifaddrs* ifp) {
+ struct ifaddrs* n;
+ while (ifp) {
+ n = ifp->ifa_next;
+ free(ifp);
+ ifp = n;
+ }
+}
diff --git a/sdk/lib/fdio/fdio.symbols.api b/sdk/lib/fdio/fdio.symbols.api
index 0e2a55d..d1f7851 100644
--- a/sdk/lib/fdio/fdio.symbols.api
+++ b/sdk/lib/fdio/fdio.symbols.api
@@ -75,6 +75,7 @@
fdio_watch_directory
fdio_zxio_create
fdopendir
+freeifaddrs
fstat
fstatat
fstatfs
@@ -83,6 +84,7 @@
ftruncate
futimens
getcwd
+getifaddrs
getpeername
getsockname
getsockopt
diff --git a/src/connectivity/network/netstack/fuchsia_posix_socket.go b/src/connectivity/network/netstack/fuchsia_posix_socket.go
index 87091cd..b5182d9 100644
--- a/src/connectivity/network/netstack/fuchsia_posix_socket.go
+++ b/src/connectivity/network/netstack/fuchsia_posix_socket.go
@@ -11,6 +11,7 @@
"net"
"reflect"
"runtime"
+ "sort"
"strings"
"sync"
"sync/atomic"
@@ -19,10 +20,13 @@
"syscall/zx/zxsocket"
"syscall/zx/zxwait"
+ "go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/fidlconv"
+ "go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/link"
"go.fuchsia.dev/fuchsia/src/lib/component"
syslog "go.fuchsia.dev/fuchsia/src/lib/syslog/go"
"fidl/fuchsia/io"
+ fidlnet "fidl/fuchsia/net"
"fidl/fuchsia/posix/socket"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -43,6 +47,7 @@
#cgo CFLAGS: -I${SRCDIR}/../../../../zircon/third_party/ulib/musl/include
#include <errno.h>
#include <fcntl.h>
+#include <net/if.h>
#include <netinet/in.h>
*/
import "C"
@@ -1276,6 +1281,71 @@
return socket.ProviderInterfaceNameToIndexResultWithErr(int32(zx.ErrNotFound)), nil
}
+func (sp *providerImpl) GetInterfaceAddresses(fidl.Context) ([]socket.InterfaceAddresses, error) {
+ nicInfos := sp.ns.stack.NICInfo()
+
+ resultInfos := make([]socket.InterfaceAddresses, 0, len(nicInfos))
+ for id, info := range nicInfos {
+ // Ensure deterministic API response.
+ sort.Slice(info.ProtocolAddresses, func(i, j int) bool {
+ x, y := info.ProtocolAddresses[i], info.ProtocolAddresses[j]
+ if x.Protocol != y.Protocol {
+ return x.Protocol < y.Protocol
+ }
+ ax, ay := x.AddressWithPrefix, y.AddressWithPrefix
+ if ax.Address != ay.Address {
+ return ax.Address < ay.Address
+ }
+ return ax.PrefixLen < ay.PrefixLen
+ })
+
+ addrs := make([]fidlnet.Subnet, 0, len(info.ProtocolAddresses))
+ for _, a := range info.ProtocolAddresses {
+ if a.Protocol != ipv4.ProtocolNumber && a.Protocol != ipv6.ProtocolNumber {
+ continue
+ }
+ addrs = append(addrs, fidlnet.Subnet{
+ Addr: fidlconv.ToNetIpAddress(a.AddressWithPrefix.Address),
+ PrefixLen: uint8(a.AddressWithPrefix.PrefixLen),
+ })
+ }
+
+ var resultInfo socket.InterfaceAddresses
+ resultInfo.SetId(uint64(id))
+ resultInfo.SetName(info.Name)
+ resultInfo.SetAddresses(addrs)
+
+ // gVisor assumes interfaces are always up, which is not the case on Fuchsia,
+ // so overwrite it with Fuchsia's interface state.
+ ifs := info.Context.(*ifState)
+ var bits uint32
+ flags := info.Flags
+ if flags.Running {
+ bits |= C.IFF_RUNNING
+ }
+ if flags.Promiscuous {
+ bits |= C.IFF_PROMISC
+ }
+ if flags.Loopback {
+ bits |= C.IFF_LOOPBACK
+ }
+ ifs.mu.Lock()
+ if ifs.mu.state == link.StateStarted {
+ bits |= C.IFF_UP
+ }
+ ifs.mu.Unlock()
+ resultInfo.SetFlags(bits)
+
+ resultInfos = append(resultInfos, resultInfo)
+ }
+
+ // Ensure deterministic API response.
+ sort.Slice(resultInfos, func(i, j int) bool {
+ return resultInfos[i].Id < resultInfos[j].Id
+ })
+ return resultInfos, nil
+}
+
func tcpipErrorToCode(err *tcpip.Error) int32 {
if err != tcpip.ErrConnectStarted {
if pc, file, line, ok := runtime.Caller(1); ok {
diff --git a/src/connectivity/network/netstack3/src/bindings/socket/mod.rs b/src/connectivity/network/netstack3/src/bindings/socket/mod.rs
index cb5f8da..1569ee0 100644
--- a/src/connectivity/network/netstack3/src/bindings/socket/mod.rs
+++ b/src/connectivity/network/netstack3/src/bindings/socket/mod.rs
@@ -143,6 +143,10 @@
psocket::ProviderRequest::Socket2 { domain, type_, protocol: _, responder } => {
responder_send!(responder, &mut self.socket(domain, type_));
}
+ psocket::ProviderRequest::GetInterfaceAddresses { responder } => {
+ // TODO(https://fxbug.dev/54162): implement this method.
+ responder_send!(responder, &mut std::iter::empty());
+ }
}
}
diff --git a/src/connectivity/network/tests/BUILD.gn b/src/connectivity/network/tests/BUILD.gn
index ec17a69..6925969 100644
--- a/src/connectivity/network/tests/BUILD.gn
+++ b/src/connectivity/network/tests/BUILD.gn
@@ -20,6 +20,7 @@
":netstack_external_network_test_client($host_toolchain)",
":netstack_if_nameindex_test($host_toolchain)",
"benchmarks",
+ "getifaddrs:tests",
"integration:tests",
]
}
diff --git a/src/connectivity/network/tests/getifaddrs/BUILD.gn b/src/connectivity/network/tests/getifaddrs/BUILD.gn
new file mode 100644
index 0000000..f2bbf34
--- /dev/null
+++ b/src/connectivity/network/tests/getifaddrs/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/test.gni")
+import("//src/sys/build/components.gni")
+
+test("getifaddrs-test") {
+ if (is_linux || is_fuchsia) {
+ sources = [ "getifaddrs_test.cc" ]
+ }
+ deps = [ "//src/lib/fxl/test:gtest_main" ]
+}
+
+fuchsia_component("getifaddrs-test-component") {
+ testonly = true
+ manifest = "meta/getifaddrs-test.cmx"
+ deps = [ ":getifaddrs-test" ]
+}
+
+fuchsia_component("getifaddrs-netemul-test") {
+ testonly = true
+ manifest = "meta/getifaddrs-netemul-test.cmx"
+ deps = [ ":getifaddrs-test-component" ]
+}
+
+fuchsia_test_package("getifaddrs-tests") {
+ test_components = [ ":getifaddrs-netemul-test" ]
+}
+
+group("tests") {
+ testonly = true
+
+ deps = [
+ ":getifaddrs-test($host_toolchain)",
+ ":getifaddrs-tests",
+
+ # TODO(brunodalbo): move this to component level when netemul can handle it.
+ "//src/connectivity/network/testing/netemul",
+ ]
+}
diff --git a/src/connectivity/network/tests/getifaddrs/getifaddrs_test.cc b/src/connectivity/network/tests/getifaddrs/getifaddrs_test.cc
new file mode 100644
index 0000000..115acd5
--- /dev/null
+++ b/src/connectivity/network/tests/getifaddrs/getifaddrs_test.cc
@@ -0,0 +1,136 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <ifaddrs.h>
+// <net/if.h> doesn't contain the full list of interface flags on Linux.
+#if defined(__linux__)
+#include <linux/if.h>
+#else
+#include <net/if.h>
+#endif
+
+#include <algorithm>
+#include <string>
+#include <tuple>
+#include <unordered_set>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace {
+
+uint8_t count_prefix(const uint8_t* mask, size_t len) {
+ uint8_t l = 0;
+ for (size_t i = 0; i < len; i++) {
+ auto m = mask[i];
+ for (size_t j = 0; j < sizeof(mask); j++) {
+ if (m) {
+ l++;
+ m <<= 1;
+ } else {
+ return l;
+ }
+ }
+ }
+ return l;
+}
+
+TEST(GetIfAddrsTest, GetIfAddrsTest) {
+ const uint32_t unsupported_flags = IFF_BROADCAST | IFF_DEBUG | IFF_POINTOPOINT | IFF_NOTRAILERS |
+ IFF_NOARP | IFF_ALLMULTI | IFF_MASTER | IFF_SLAVE |
+ IFF_MULTICAST | IFF_PORTSEL | IFF_AUTOMEDIA | IFF_DYNAMIC |
+ IFF_LOWER_UP | IFF_DORMANT | IFF_ECHO;
+
+ // Fields of this tuple are: interface_name, address, prefix_length, scope_id, flags.
+ using InterfaceAddress = std::tuple<std::string, std::string, uint8_t, uint32_t, uint32_t>;
+
+ std::vector<InterfaceAddress> want_ifaddrs{
+ std::make_tuple("lo", "127.0.0.1", 8, 0, IFF_LOOPBACK | IFF_UP | IFF_RUNNING),
+ std::make_tuple("lo", "::1", 128, 0, IFF_LOOPBACK | IFF_UP | IFF_RUNNING),
+ };
+ const size_t lo_addrs_count = want_ifaddrs.size();
+
+#if defined(__Fuchsia__)
+ want_ifaddrs.push_back(std::make_tuple("ep1", "192.168.0.1", 20, 0, IFF_UP | IFF_RUNNING));
+ want_ifaddrs.push_back(std::make_tuple("ep2", "192.168.0.2", 15, 0, IFF_UP | IFF_RUNNING));
+ want_ifaddrs.push_back(std::make_tuple("ep3", "fe80::1", 64, 4, IFF_UP | IFF_RUNNING));
+ want_ifaddrs.push_back(std::make_tuple("ep4", "1234::5:6:7:8", 120, 0, IFF_UP | IFF_RUNNING));
+#endif
+
+ struct ifaddrs* ifaddr;
+ ASSERT_EQ(getifaddrs(&ifaddr), 0) << strerror(errno);
+
+ std::vector<InterfaceAddress> got_ifaddrs;
+ // Expect one auto-generated link-local address per non-loopback interface.
+ const size_t want_unknown_link_local_addrs = want_ifaddrs.size() - lo_addrs_count;
+ size_t got_unknown_link_local_addrs = 0;
+
+ for (auto it = ifaddr; it != nullptr; it = it->ifa_next) {
+ const auto if_name = std::string(it->ifa_name);
+#if defined(__linux__)
+ // Only loopback is consistent on host environments.
+ if (if_name != "lo") {
+ continue;
+ }
+#endif
+
+ switch (it->ifa_addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(it->ifa_addr);
+ char sin_addr_buf[INET_ADDRSTRLEN];
+ const char* sin_addr =
+ inet_ntop(AF_INET, &addr_in->sin_addr, sin_addr_buf, INET_ADDRSTRLEN);
+
+ const sockaddr_in* netmask = reinterpret_cast<sockaddr_in*>(it->ifa_netmask);
+ const uint8_t prefix_len =
+ count_prefix(reinterpret_cast<const uint8_t*>(&netmask->sin_addr.s_addr), 4);
+
+ got_ifaddrs.push_back(std::make_tuple(if_name, std::string(sin_addr), prefix_len, 0,
+ it->ifa_flags & ~unsupported_flags));
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6* addr_in6 = reinterpret_cast<sockaddr_in6*>(it->ifa_addr);
+ char sin6_addr_buf[INET6_ADDRSTRLEN];
+ const char* sin6_addr =
+ inet_ntop(AF_INET6, &(addr_in6->sin6_addr), sin6_addr_buf, INET6_ADDRSTRLEN);
+
+ const std::string sin6_addr_str = std::string(sin6_addr);
+
+ const bool is_known_addr = std::any_of(want_ifaddrs.begin(), want_ifaddrs.end(),
+ [sin6_addr_str](const InterfaceAddress& ifaddr) {
+ return std::get<1>(ifaddr) == sin6_addr_str;
+ });
+
+ // Skip and count auto-generated link-local addresses.
+ if (IN6_IS_ADDR_LINKLOCAL(addr_in6->sin6_addr.s6_addr) && !is_known_addr) {
+ got_unknown_link_local_addrs++;
+ continue;
+ }
+
+ const sockaddr_in6* netmask = reinterpret_cast<sockaddr_in6*>(it->ifa_netmask);
+ const uint8_t prefix_len = count_prefix(netmask->sin6_addr.s6_addr, 16);
+
+ got_ifaddrs.push_back(std::make_tuple(if_name, sin6_addr_str, prefix_len,
+ addr_in6->sin6_scope_id,
+ it->ifa_flags & ~unsupported_flags));
+ break;
+ }
+ case AF_PACKET:
+ // Ignore AF_PACKET addresses because raw sockets are not supported on Fuchsia.
+ continue;
+ default:
+ GTEST_FAIL() << "unexpected address family " << it->ifa_addr->sa_family;
+ }
+ }
+
+ EXPECT_EQ(got_ifaddrs, want_ifaddrs);
+ EXPECT_EQ(got_unknown_link_local_addrs, want_unknown_link_local_addrs);
+
+ freeifaddrs(ifaddr);
+}
+
+} // namespace
diff --git a/src/connectivity/network/tests/getifaddrs/meta/getifaddrs-netemul-test.cmx b/src/connectivity/network/tests/getifaddrs/meta/getifaddrs-netemul-test.cmx
new file mode 100644
index 0000000..a742b2f
--- /dev/null
+++ b/src/connectivity/network/tests/getifaddrs/meta/getifaddrs-netemul-test.cmx
@@ -0,0 +1,78 @@
+{
+ "facets": {
+ "fuchsia.netemul": {
+ "environment": {
+ "services": {
+ "fuchsia.net.stack.Stack": "fuchsia-pkg://fuchsia.com/netstack#meta/netstack_debug.cmx",
+ "fuchsia.netstack.Netstack": "fuchsia-pkg://fuchsia.com/netstack#meta/netstack_debug.cmx",
+ "fuchsia.posix.socket.Provider": "fuchsia-pkg://fuchsia.com/netstack#meta/netstack_debug.cmx"
+ },
+ "setup": [
+ {
+ "arguments": [
+ "-e",
+ "ep1",
+ "-i",
+ "192.168.0.1/20"
+ ],
+ "url": "fuchsia-pkg://fuchsia.com/netemul_sandbox#meta/helper_netstack_cfg.cmx"
+ },
+ {
+ "arguments": [
+ "-e",
+ "ep2",
+ "-i",
+ "192.168.0.2/15"
+ ],
+ "url": "fuchsia-pkg://fuchsia.com/netemul_sandbox#meta/helper_netstack_cfg.cmx"
+ },
+ {
+ "arguments": [
+ "-e",
+ "ep3",
+ "-i",
+ "fe80::1/64"
+ ],
+ "url": "fuchsia-pkg://fuchsia.com/netemul_sandbox#meta/helper_netstack_cfg.cmx"
+ },
+ {
+ "arguments": [
+ "-e",
+ "ep4",
+ "-i",
+ "1234::5:6:7:8/120"
+ ],
+ "url": "fuchsia-pkg://fuchsia.com/netemul_sandbox#meta/helper_netstack_cfg.cmx"
+ }
+ ],
+ "test": [
+ "fuchsia-pkg://fuchsia.com/getifaddrs-tests#meta/getifaddrs-test-component.cmx"
+ ]
+ },
+ "networks": [
+ {
+ "endpoints": [
+ {
+ "name": "ep1"
+ },
+ {
+ "name": "ep2"
+ },
+ {
+ "name": "ep3"
+ },
+ {
+ "name": "ep4"
+ }
+ ],
+ "name": "net"
+ }
+ ],
+ "timeout": 120
+ }
+ },
+ "program": {
+ "binary": "test/getifaddrs-netemul-test"
+ },
+ "runner": "fuchsia-pkg://fuchsia.com/netemul_runner#meta/netemul_runner.cmx"
+}
diff --git a/src/connectivity/network/tests/getifaddrs/meta/getifaddrs-test.cmx b/src/connectivity/network/tests/getifaddrs/meta/getifaddrs-test.cmx
new file mode 100644
index 0000000..2c1aba7
--- /dev/null
+++ b/src/connectivity/network/tests/getifaddrs/meta/getifaddrs-test.cmx
@@ -0,0 +1,11 @@
+{
+ "program": {
+ "binary": "test/getifaddrs-test"
+ },
+ "sandbox": {
+ "services": [
+ "fuchsia.net.stack.Stack",
+ "fuchsia.posix.socket.Provider"
+ ]
+ }
+}
diff --git a/zircon/third_party/ulib/musl/src/network/getifaddrs.c b/zircon/third_party/ulib/musl/src/network/getifaddrs.c
index 7ca9a6e..70bf1a5 100644
--- a/zircon/third_party/ulib/musl/src/network/getifaddrs.c
+++ b/zircon/third_party/ulib/musl/src/network/getifaddrs.c
@@ -2,15 +2,6 @@
#include "getifaddrs.h"
-void freeifaddrs(struct ifaddrs* ifp) {
- struct ifaddrs* n;
- while (ifp) {
- n = ifp->ifa_next;
- free(ifp);
- ifp = n;
- }
-}
-
static int netlink_msg_to_ifaddr(void* pctx, struct nlmsghdr* h) {
struct ifaddrs_ctx* ctx = pctx;
struct ifaddrs_storage *ifs, *ifs0 = NULL;
@@ -122,15 +113,3 @@
}
return 0;
}
-
-int getifaddrs(struct ifaddrs** ifap) {
- struct ifaddrs_ctx _ctx, *ctx = &_ctx;
- int r;
- memset(ctx, 0, sizeof *ctx);
- r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
- if (r == 0)
- *ifap = &ctx->first->ifa;
- else
- freeifaddrs(&ctx->first->ifa);
- return r;
-}
diff --git a/zircon/third_party/ulib/musl/stubs/socketstubs.c b/zircon/third_party/ulib/musl/stubs/socketstubs.c
index 5ca3cf2..429c835 100644
--- a/zircon/third_party/ulib/musl/stubs/socketstubs.c
+++ b/zircon/third_party/ulib/musl/stubs/socketstubs.c
@@ -1,5 +1,6 @@
#define _GNU_SOURCE
#include <errno.h>
+#include <ifaddrs.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -118,3 +119,12 @@
return -1;
}
weak_alias(stub_sockatmark, sockatmark);
+
+static int stub_getifaddrs(struct ifaddrs** ifap) {
+ errno = ENOSYS;
+ return -1;
+}
+weak_alias(stub_getifaddrs, getifaddrs);
+
+static void stub_freeifaddrs(struct ifaddrs* ifp) {}
+weak_alias(stub_freeifaddrs, freeifaddrs);